从 Java 访问 Scala 嵌套类

Posted

技术标签:

【中文标题】从 Java 访问 Scala 嵌套类【英文标题】:Accessing Scala nested classes from Java 【发布时间】:2015-08-28 19:37:45 【问题描述】:

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

object Foo 
  class Bar

我们可以使用new Foo.Bar() 在Java 中轻松构造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】:

让我们给这两个版本起不同的名字,让他们更容易谈论:

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 -vFoo2$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 解释为某种内部类,它会让你创建一个带有 @ 的实例987654340@。所以这是一种解决方法,只是不是很漂亮。

为什么 Scala 编译器对待 Foo1Bar2 不同(从某种意义上说,Bar2 没有得到 Bar2 类),以及为什么 InnerClasses 属性中列出的封闭类Baz2 末尾有一个美元符号,而 Bar1 没有?我真的没有任何想法。但这就是区别——您只需要更详细一点即可通过javap 看到它。

【讨论】:

以上是关于从 Java 访问 Scala 嵌套类的主要内容,如果未能解决你的问题,请参考以下文章

Scala 中的 C++ 嵌套类

从嵌套类到包含类的 C# 成员访问 [重复]

java内部类的静态嵌套类

java 嵌套类

Scala--嵌套类

Swift 嵌套类属性