讓我們給這兩個版本不同的名稱,使他們更容易一些談:
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
來看它。