从Java访问Scala嵌套类

时间:2015-06-12 17:35:33

标签: java scala

假设我们在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类之间的区别是什么?

1 个答案:

答案 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$Baz2new Foo2$Bar2$Baz2()(在Foo1没有获得Bar2类的意义上),为什么封闭在Bar2 Bar2属性中列出的类在最后有一个美元符号,而InnerClasses的那个没有?我真的不知道。但这就是区别 - 你需要更加详细一点才能看到它Baz2