让我们给这两个版本不同的名称,使他们更容易一些谈:
object Foo1 {
class Bar1
}
object Foo2 {
object Bar2 {
class Baz2
}
}
现在,如果你看一下类文件,你会看到,Scala编译器创建了一个Foo1
类。当您在运行Foo1$Bar1
javap -v
,你会看到那类被列为封闭类:
InnerClasses:
public statiC#14= #2 of #13; //Bar1=class Foo1$Bar1 of class Foo1
这正是将在Java的静态嵌套类发生什么,所以Java编译器是心甘情愿为你编译new Foo1.Bar1()
。
现在看javap -v
输出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$
,不Foo2$Bar2
(事实上,Scala编译器甚至不产生Foo2$Bar2
除非你添加一个伴侣类object Bar2
)。 Java编译器期望封闭类Foo2$Bar2$
的静态内部类Baz2
被命名为Foo2$Bar2$$Baz2
,带有两个美元符号。这与它实际得到的不匹配(Foo2$Bar2$Baz2
),所以它对new Foo2.Bar2.Baz2()
说不。
Java非常乐意接受类名中的美元符号,在这种情况下,由于它无法弄清楚如何将Foo2$Bar2$Baz2
解释为某种内部类,它可以让您创建一个带有new Foo2$Bar2$Baz2()
的实例。所以这是一个解决方法,只是不是很漂亮。
为什么Scala编译器把Foo1
和Bar2
不同(在这个意义上,Bar2
没有得到一个Bar2
类),以及为什么在InnerClasses
属性为Baz2
列出的封装类对最终美元符号,而一个为Bar1
不?我真的不知道。但这就是区别 - 你只需要更详细一点就可以用javap
来看它。