本文介绍了从 Java 访问 Scala 嵌套类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Let's say we have the following class structure in Scala.

object Foo {
  class Bar
}

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

We can easily construct Bar in Java with new Foo.Bar(). But everything changes when we add an extra level of nested classes.

object Foo {
  object Bar {
    class Baz
  }
}

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

Somehow, it's no longer possible to construct the most inner class Baz in Java. Looking at the javap output, I can't see any significant difference between first (2 levels) and second cases (3 levels). Generated code looks pretty reasonable to me.

2 级:

public class Foo$Bar { ... }

3 级

public class Foo$Bar$Baz { ... }

话虽如此,当从 Java 访问时,2 级和 3 级嵌套 Scala 类之间有什么区别?

With that said, what's the difference between 2-level vs. 3-level nested Scala classes when they accessed from Java?

推荐答案

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

Let's give the two versions different names to make them a little easier to talk about:

object Foo1 {
  class Bar1
}

object Foo2 {
  object Bar2 {
    class Baz2
  }
}

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

Now if you look at the class files, you'll see that the Scala compiler has created a Foo1 class. When you run javap -v on Foo1$Bar1, you'll see that that class is listed as the enclosing class:

InnerClasses:
     public static #14= #2 of #13; //Bar1=class Foo1$Bar1 of class Foo1

这正是 Java 中的静态嵌套类会发生的情况,因此 Java 编译器非常乐意为您编译 new Foo1.Bar1().

This is exactly what would happen with a static nested class in Java, so the Java compiler is perfectly happy to compile new Foo1.Bar1() for you.

现在查看 Foo2$Bar2$Baz2javap -v 输出:

Now look at the javap -v output for 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() 说不.

Now the enclosing class is Foo2$Bar2$, not Foo2$Bar2 (in fact the Scala compiler doesn't even generate a Foo2$Bar2 unless you add a companion class for object Bar2). The Java compiler expects a static inner class Baz2 of a enclosing class Foo2$Bar2$ to be named Foo2$Bar2$$Baz2, with two dollar signs. This doesn't match what it's actually got (Foo2$Bar2$Baz2), so it says no to new Foo2.Bar2.Baz2().

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

Java is perfectly happy to accept dollar signs in class names, and in this case since it can't figure out how to interpret Foo2$Bar2$Baz2 as an inner class of some kind, it'll let you create an instance with new Foo2$Bar2$Baz2(). So that's a workaround, just not a very pretty one.

为什么 Scala 编译器对 Foo1Bar2 的处理方式不同(在这个意义上,Bar2 没有得到 Bar2 类),以及为什么 Baz2InnerClasses 属性中列出的封闭类在末尾有一个美元符号,而 Bar1 没有?我真的没有任何想法.但这就是区别——你只需要更详细一点就可以用 javap 看到它.

Why does the Scala compiler treat Foo1 and Bar2 differently (in the sense that Bar2 doesn't get a Bar2 class), and why does the enclosing class listed in the InnerClasses attribute for Baz2 have a dollar sign on the end, while the one for Bar1 doesn't? I don't really have any idea. But that's the difference—you just need a little more verbosity to see it with javap.

这篇关于从 Java 访问 Scala 嵌套类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-21 13:40