从Java访问Scala嵌套类

Vla*_*kov 13 java scala

假设我们在Scala中有以下类结构.

object Foo {
  class Bar
}
Run Code Online (Sandbox Code Playgroud)

我们可以Bar用Java 轻松构造new Foo.Bar().但是当我们添加额外级别的嵌套类时,一切都会改变.

object Foo {
  object Bar {
    class Baz
  }
}
Run Code Online (Sandbox Code Playgroud)

不知何故,Baz在Java中构建最内部的类已经不可能了.看javap输出,我看不出第一(2级)和第二级(3级)之间有任何显着差异.生成的代码对我来说看起来很合理.

2个级别:

public class Foo$Bar { ... }
Run Code Online (Sandbox Code Playgroud)

3个级别

public class Foo$Bar$Baz { ... }
Run Code Online (Sandbox Code Playgroud)

话虽如此,当他们从Java访问时,2级与3级嵌套Scala类之间的区别是什么?

Tra*_*own 13

让我们给两个版本不同的名称,让它们更容易讨论:

object Foo1 {
  class Bar1
}

object Foo2 {
  object Bar2 {
    class Baz2
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,如果查看类文件,您将看到Scala编译器已创建了一个Foo1类.运行javap -vFoo1$Bar1,您将看到该类被列为封闭类:

InnerClasses:
     public static #14= #2 of #13; //Bar1=class Foo1$Bar1 of class Foo1
Run Code Online (Sandbox Code Playgroud)

这正是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$
Run Code Online (Sandbox Code Playgroud)

现在封闭类Foo2$Bar2$不是Foo2$Bar2(实际上Scala编译器甚至不会生成一个,Foo2$Bar2除非你为它添加一个伴随类object Bar2).Java编译器期望命名Baz2一个封闭类的静态内部类,带有两个美元符号.这与它实际得到的不匹配(),所以它说不.Foo2$Bar2$Foo2$Bar2$$Baz2Foo2$Bar2$Baz2new Foo2.Bar2.Baz2()

Java非常乐意接受类名中的美元符号,在这种情况下,因为它无法弄清楚如何将其解释Foo2$Bar2$Baz2为某种类型的内部类,所以它可以让你创建一个实例new Foo2$Bar2$Baz2().所以这是一个解决方法,只是不是一个非常漂亮的.

为什么Scala编译器治疗Foo1Bar2不同(在这个意义上,Bar2没有得到一Bar2类),以及为什么在列出的封装类InnerClasses属性为Baz2对最终美元符号,而一个Bar1不?我真的不知道.但这就是区别 - 你需要更多的冗长才能看到它javap.