可能类似问题Why can outer Java classes access inner class private members?或Access to superclass private fields using the super keyword in a subclass。
但是存在一些差异:子类可以访问其父级的私有成员(以及仅最近的父级)类。
给出以下示例代码:
public class T {
private int t;
class T1 {
private int t1;
public void test() {
System.out.println(t);
}
}
class T2 extends T1 {
private int t2;
public void test() {
System.out.println(t);
System.out.println(super.t1);
System.out.println(this.t2);
}
}
class T3 extends T2 {
public void test() {
System.out.println(t);
System.out.println(super.t1); // NG: t1 Compile error! Why?
System.out.println(super.t2); // OK: t2 OK
}
}
}
答案 0 :(得分:50)
聪明的例子!但这实际上是一个有点无聊的解释 - 没有可见性问题,你根本无法直接从t1
引用T3
因为super.super
isn't allowed。
T2
无法直接访问自己的t1
字段,因为它是私有的(并且子类不会继承其父级的私有字段),但super
实际上是{的实例{1}}由于它位于同一个班级T1
,因此可以引用T2
的私有字段。 super
没有机制直接处理其祖父母类T3
的私有字段。
这两个都在T1
内编译得很好,这表明T3
可以访问其祖父母的T3
字段:
private
相反,这不会在System.out.println(((T1)this).t1);
System.out.println(new T1().t1);
或T2
中编译:
T3
如果允许System.out.println(t1);
,您可以从super.super
执行此操作:
T3
如果我定义了3个类,
System.out.println(super.super.t1);
,A
,B
,C
具有受保护的字段A
和t1
继承自B
的{{1}}和A
,C
可以通过调用B
来引用C
sA
,因为它这里可见。逻辑上应该不适用于内部类继承,即使该字段是私有的,因为这些私有成员应该是可见的,因为它们属于同一个类?
(为简单起见,我将坚持使用OP的t1
,super.t1
和T1
类名称。
如果T2
为T3
,则没有任何问题 - t1
可以直接引用protected
字段,就像任何子类一样。问题出现在T3
,因为某个类没有感知其父类的t1
字段,因此无法直接引用它们,即使在实践中它们是可见的。这就是为什么你必须使用private
中的private
,以便甚至引用相关字段。
即使super.t1
涉及它没有T2
字段,它也可以通过位于同一个外部类中访问T3
个t1
字段。既然如此,您需要做的就是将T1
转换为private
,并且您可以引用私有字段。 this
中的T1
电话(实质上)将super.t1
投射到T2
,让我们引用其字段。
答案 1 :(得分:15)
从技术上讲,在 JVM 级别,您可以不访问另一个类的任何private
成员 - 也不能访问封闭类的成员{{1} }),也不是父类(T.t
)的那些。在您的代码中,您可以看起来像,因为编译器会在访问的类中为您生成synthetic
访问器方法。使用正确的表单T2.t2
在T3
课程中修复无效的引用 时,会发生同样的情况。super.t1
借助此类编译器生成的 ((T1) this).t1
访问器方法,您通常可以访问 的任何 synthetic
成员类嵌套在外(顶级)private
类中,例如来自T
,您可以使用T1
。请注意,这也适用于new T2().t2
成员。
JDK 1.1版中引入了 private static
属性,以支持嵌套类,这是当时java中的一种新语言功能。从那时起, JLS 明确允许对顶级类中的所有成员进行相互访问,包括synthetic
个。
但是为了向后兼容,编译器会打开嵌套类(例如private
,T$T1
,T$T2
)并翻译T$T3
成员访问 调用以生成 private
访问者方法(这些方法因此需要将包私有,即默认> em>,visibility(可见性):
synthetic
N.B。:您不能直接引用 class T {
private int t;
T() { // generated
super(); // new Object()
}
static synthetic int access$t(T t) { // generated
return t.t;
}
}
class T$T1 {
private int t1;
final synthetic T t; // generated
T$T1(T t) { // generated
this.t = t;
super(); // new Object()
}
static synthetic int access$t1(T$T1 t$t1) { // generated
return t$t1.t1;
}
}
class T$T2 extends T$T1 {
private int t2;
{
System.out.println(T.access$t((T) this.t)); // t
System.out.println(T$T1.access$t1((T$T1) this)); // super.t1
System.out.println(this.t2);
}
final synthetic T t; // generated
T$T2(T t) { // generated
this.t = t;
super(this.t); // new T1(t)
}
static synthetic int access$t2(T$T2 t$t2) { // generated
return t$t2.t2;
}
}
class T$T3 extends T$T2 {
{
System.out.println(T.access$t((T) this.t)); // t
System.out.println(T$T1.access$t1((T$T1) this)); // ((T1) this).t1
System.out.println(T$T2.access$t2((T$T2) this)); // super.t2
}
final synthetic T t; // generated
T$T3(T t) { // generated
this.t = t;
super(this.t); // new T2(t)
}
}
成员,因此在源代码中您无法使用,例如synthetic
你自己。
答案 2 :(得分:7)
非常好的发现!我想,我们都假设您的代码示例应该编译。
不幸的是,事实并非如此......而JLS在§15.11.2. "Accessing Superclass Members using super"给我们答案(强调我的):
假设字段访问表达式super.f出现在C类中,并且C的 immediate 超类是S类。如果S中的f可以从C类(第6.6节)访问,那么超级.f被视为在类S的主体中是表达式this.f.否则,发生编译时错误。
提供辅助功能,因为所有字段都在同一个封闭类中。它们可以是私人的,但仍然可以访问。
问题在于return serviceA(args)
.or(() -> serviceB(args))
.or(() -> serviceC(args));
(T2
的立即超类)将T3
视为super.t1
是非法的 - 有this.t1
中没有字段t1
。因此编译错误。