众所周知,私有字段不会在类之间继承。令我着迷的是它如何用于内部静态类。考虑以下代码:
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”构造实现?
内部类是Java的较晚入门。添加它们时,它们仅作为编译器扩展添加,对JVM不变。
语言规范指出,内部类被允许访问在其内声明的类的私有成员。包括其他内部类。
为了使其工作,编译器会生成桥接方法。上面示例中的javap与Main $ A一起使用看起来像这样:
注意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的生成代码。注意对access $ 200和300的调用,它们出现在Java代码中super.a和super.foo()的位置。
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”构造实现?
私有字段通常不属于编译器用于字段的解析路径的一部分,通过迫使开发人员指定超级字段,编译器可以确定私有访问是什么意思,而不是错误。