问题描述
假设我们在 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$Baz2
的 javap -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 编译器对 Foo1
和 Bar2
的处理方式不同(在这个意义上,Bar2
没有得到 Bar2
类),以及为什么 Baz2
的 InnerClasses
属性中列出的封闭类在末尾有一个美元符号,而 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 嵌套类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!