访问父类的私有字段

3
众所周知,私有字段不会在类之间继承。但是,我很好奇内部静态类的情况。 考虑以下代码:
public class Main {
    public static void main(String[] args) {
        new B();
    }

    private static class A {
        private int a = 10;

        private void foo() {
            System.out.println("A.foo");
        }
    }

    private static class B extends A {
        {
            // foo();    // compile-time error
            super.foo();    // ok

            // System.out.println(a);    // compile-time error
            System.out.println(super.a);    // ok
        }
    }
}

您能解释一下如何访问其他内部类的私有字段吗?如果这是合法的,为什么只能通过“super.XXX”结构访问呢?


我认为修饰符只与外部类有关。内部类则不同... - Oliver Watkins
2个回答

3
内部类是Java中的后期加入。当它们被添加时,它们仅作为编译器扩展添加,没有更改JVM。
语言规范规定,内部类可以访问其声明所在类的私有成员,包括其他内部类。
为使其正常工作,编译器生成桥接方法。使用上面示例中的Main $ A运行javap命令,结果如下所示:
请注意,添加了access$200和access$300。 它们提供了对私有方法和字段的后门访问。
class Main$A {
  Main$A(Main$1);
    Code:
       0: aload_0       
       1: invokespecial #3                  // Method "<init>":()V
       4: return        

  static void access$200(Main$A);
    Code:
       0: aload_0       
       1: invokespecial #2                  // Method foo:()V
       4: return        

  static int access$300(Main$A);
    Code:
       0: aload_0       
       1: getfield      #1                  // Field a:I
       4: ireturn       
}

为了完整起见,这里是 Main$B 的生成代码。请注意,在 Java 代码中出现 super.a 和 super.foo() 的地方,它们被替换成了 access$200 和 300 的调用。

class Main$B extends Main$A {
  public Main$B();
    Code:
       0: aload_0       
       1: aconst_null   
       2: invokespecial #1                  // Method Main$A."<init>":(LMain$1;)V
       5: aload_0       
       6: invokestatic  #2                  // Method Main$A.access$100:(LMain$A;)V
       9: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      12: aload_0       
      13: invokestatic  #4                  // Method Main$A.access$200:(LMain$A;)I
      16: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
      19: return        
}

如果这是合法的,为什么只能通过 "super.XXX" 结构实现呢?

私有字段通常不是编译器解析字段的路径的一部分,通过强制开发人员指定 super,编译器确保私有访问是所需的,而不是一个错误。


好的,如果我理解正确:当我使用“super.XXX”结构时,会调用access$200和access$300? - szimon

0

来自JLS3 6.6.1:“私有类成员或构造函数仅在包含该成员或构造函数的顶级类(§7.6)的主体内部可访问。它不会被子类继承。

由于内部类在顶级类的主体内部可访问,因此它是可访问的,而子类则不在封闭类之内。 现在规范并没有说明应该如何实现这一点 - 这并不是规范的工作。实际上,这取决于实现程序员使其发生的方式,而这些细节在当前规范中没有记录。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接