2014-09-23 168 views
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”构造才有可能?

+0

我认为修饰符只与外部类有关。内部类都崩溃了...... – 2014-09-23 09:24:42

回答

3

内部类是Java的晚期入门。添加它们时,它们仅作为编译器扩展添加,不会更改为JVM。

语言规范声明允许内部类访问它内部声明的类的私有成员;包括其他内部类。

为了使它工作,编译器生成桥接方法。从上面的例子中使用主$ A的javap看起来像这样:

注意访问额外$ 200和访问$ 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代码。注意访问$ 200和300的调用,它们出现在super.a和super.foo()出现在Java代码中的地方。

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”构造是可能的吗?

私有字段通常不是字段的编译器解析路径的一部分,通过强制开发人员指定超级编译器确保私有访问是指什么意思而不是错误。

+0

好吧,如果我理解正确:当我使用“super.XXX”构造时,访问$ 200和访问$ 300被调用? – SzymonK 2014-09-23 09:41:14

+0

@szimon是的,正确的。 – 2014-09-23 09:42:31

0

JLS3 6.6.1:“A私有类成员或构造方法只在顶层类(第7.6节)包围的成员或构造的声明体是接近它不是由子类继承..

由于内部类在顶级类的内部是可访问的,因此它的可访问类和子类不在封闭类中。 现在规范并没有说明这是怎么发生的 - 这不是真正的规范工作。给实现程序员以实现它,并且这些细节没有记录在当前的规范中。