2015-06-12 83 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来看它。