2015-06-12 109 views
12

假設我們在Scala中有以下類結構。從Java訪問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 { ... } 

雖這麼說,什麼是嵌套Scala類,當他們從Java訪問2級與3級之間的區別?

回答

12

讓我們給這兩個版本不同的名稱,使他們更容易一些談:

object Foo1 { 
    class Bar1 
} 

object Foo2 { 
    object Bar2 { 
    class Baz2 
    } 
} 

現在,如果你看一下類文件,你會看到,Scala編譯器創建了一個Foo1類。當您在運行Foo1$Bar1javap -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編譯器把Foo1Bar2不同(在這個意義上,Bar2沒有得到一個Bar2類),以及爲什麼在InnerClasses屬性爲Baz2列出的封裝類對最終美元符號,而一個爲Bar1不?我真的不知道。但這就是區別 - 你只需要更詳細一點就可以用javap來看它。