假设我们在Scala中有以下类结构。
object Foo {
class Bar
}
我们可以使用Bar
在Java中轻松构建new Foo.Bar()
。但是当我们添加额外级别的嵌套类时,一切都会改变。
object Foo {
object Bar {
class Baz
}
}
不知何故,不再可能在Java中构造最内部的类Baz
。查看javap
输出,我看不出第一个(2个级别)和第二个案例(3个级别)之间有任何显着差异。生成的代码看起来很合理。
2个级别:
public class Foo$Bar { ... }
3级
public class Foo$Bar$Baz { ... }
话虽如此,当他们从Java访问时,2级与3级嵌套Scala类之间的区别是什么?
答案 0 :(得分:12)
让我们为这两个版本提供不同的名称,以便让它们更易于讨论:
object Foo1 {
class Bar1
}
object Foo2 {
object Bar2 {
class Baz2
}
}
现在,如果查看类文件,您将看到Scala编译器已创建Foo1
类。当您在javap -v
上运行Foo1$Bar1
时,您会看到该类被列为封闭类:
InnerClasses:
public static #14= #2 of #13; //Bar1=class Foo1$Bar1 of class Foo1
这正是Java中静态嵌套类所发生的情况,因此Java编译器非常乐意为您编译new Foo1.Bar1()
。
现在查看javap -v
的{{1}}输出:
Foo2$Bar2$Baz2
现在封闭类是InnerClasses:
public static #16= #13 of #15; //Bar2$=class Foo2$Bar2$ of class Foo2
public static #17= #2 of #13; //Baz2=class Foo2$Bar2$Baz2 of class Foo2$Bar2$
,而不是Foo2$Bar2$
(事实上,除非为{{1}添加伴随类,否则Scala编译器甚至不会生成Foo2$Bar2
})。 Java编译器期望封闭类Foo2$Bar2
的静态内部类object Bar2
被命名为Baz2
,带有两个美元符号。这与它实际得到的内容(Foo2$Bar2$
)不匹配,所以它对Foo2$Bar2$$Baz2
说不。
Java非常乐意接受类名中的美元符号,在这种情况下,因为它无法弄清楚如何将Foo2$Bar2$Baz2
解释为某种类型的内部类,所以它会让您使用new Foo2.Bar2.Baz2()
创建实例。这是一个解决方法,只是不是一个非常漂亮的。
为什么Scala编译器会以不同的方式处理Foo2$Bar2$Baz2
和new Foo2$Bar2$Baz2()
(在Foo1
没有获得Bar2
类的意义上),为什么封闭在Bar2
Bar2
属性中列出的类在最后有一个美元符号,而InnerClasses
的那个没有?我真的不知道。但这就是区别 - 你需要更加详细一点才能看到它Baz2
。