Java 内部类可见性难题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1086255/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java inner class visibility puzzle
提问by Gerard
Consider the following case:
考虑以下情况:
public class A {
public A() { b = new B(); }
B b;
private class B { }
}
From a warning in Eclipse I quote that: the java complier emulates the constructor A.B() by a synthetic accessor method. I suppose the compiler now goes ahead and creates an extra "under water" constructor for B.
我引用 Eclipse 中的警告:java 编译器通过合成访问器方法模拟构造函数 AB()。我想编译器现在继续为 B 创建一个额外的“水下”构造函数。
I feel this is rather strange: why would class B not be visible as a.k.o. field in A? And: does it mean that class B is no longer private at run time? And: why behaves the protected keyword for class B different?
我觉得这很奇怪:为什么 B 类不会作为 A 中的 ako 字段可见?并且:这是否意味着 B 类在运行时不再是私有的?并且:为什么 B 类的 protected 关键字的行为不同?
public class A {
public A() { b = new B(); }
B b;
protected class B { }
}
回答by skaffman
Inner classes are essentially a hack introduced in Java 1.1. The JVM doesn't actually have any concept of an inner class, and so the compiler has to bodge it. The compiler generates class B "outside" of class A, but in the same package, and then adds synthetic accessors/constructors to it to allow A to get access to it.
内部类本质上是 Java 1.1 中引入的一种hack。JVM 实际上没有任何内部类的概念,因此编译器必须对它进行处理。编译器在类 A 的“外部”生成类 B,但在同一个包中,然后向其中添加合成访问器/构造函数以允许 A 访问它。
When you give B a protected constructor, A can access that constructor since it's in the same package, without needing a synthetic constructor to be added.
当您给 B 一个受保护的构造函数时,A 可以访问该构造函数,因为它在同一个包中,而无需添加合成构造函数。
回答by siegi
I know this question is now almost three years old, but I find that a part of the question is still not answered:
我知道这个问题现在已经快三年了,但我发现问题的一部分仍然没有回答:
And: does it mean that class B is no longer private at run time?
并且:这是否意味着 B 类在运行时不再是私有的?
Carlos Heubergers comment on skaffmans answer suggests, class Bis still privatefor other classes in the package.
Carlos Heubergers 对 skaffmans 回答的评论表明,类B仍然private适用于包中的其他类。
He is probably right for the Java programming language, i.e. it is not possible to refer to class Bfrom an other class. At least not without using reflection (with which also private class members may be accessed from the outside), but this is another issue.
他可能适合 Java 编程语言,即不可能B从其他类中引用类。至少不是不使用反射(也可以从外部访问私有类成员),但这是另一个问题。
But as the JVM does not have any concept of an inner class (as skaffman states), I asked myself how an "accessible by only one class" visibility is realized at the bytecode level. The answer: It isn't realized at all, for the JVM the inner class looks like a normal package private class. This is, if you write bytecode for yourself (or modify one generated by the compiler) you can access class Bwithout problems.
但是由于 JVM 没有任何内部类的概念(正如 skaffman 所说),我问自己如何在字节码级别实现“仅一个类可访问”的可见性。答案:它根本没有实现,对于 JVM 来说,内部类看起来像一个普通的包私有类。也就是说,如果您为自己编写字节码(或修改编译器生成的字节码),则可以B毫无问题地访问类。
You can access all synthetic accessor methods from all classes in the same package, too. So if you assign a value to a private field of class Ain a method of class B, a synthetic accessor method with default (i.e. package private) visibility is generated in class A(named something like access$000) that sets the value for you. This method is supposed to only be called from class B(and indeed it can only be called from there using the Java language). But from the JVMs point of view, this is just a method as any other and can be called by any class.
您也可以从同一个包中的所有类访问所有合成访问器方法。因此,如果您在 classA的方法中为 class的私有字段赋值B,则会在类中生成具有默认(即包私有)可见性的合成访问器方法A(命名为类似access$000),为您设置值。这个方法应该只能从类中调用B(实际上它只能使用 Java 语言从那里调用)。但是从 JVM 的角度来看,这只是一个方法,可以被任何类调用。
So, to answer the question:
所以,回答这个问题:
- From the Java languages point of view, class
Bis and stays private. - From the JVMs point of view, class
B(or better: classA$B) is not private.
- 从 Java 语言的角度来看,类
B是并且保持私有的。 - 从 JVM 的角度来看, class
B(或更好: classA$B)不是私有的。
回答by finnw
The access of class Band its constructor do not have to be the same. You can have a private inner class with a package-scope constructor, and this is what I usually do.
class B和它的构造函数的访问不必相同。你可以有一个带有包范围构造函数的私有内部类,这就是我通常做的。
public class A {
public A() { b = new B(); }
B b;
private class B {
B() { }
}
}
回答by Ratnesh Maurya
You need to use
你需要使用
this.new B();

