2014-09-23 80 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節)包圍的成員或構造的聲明體是接近它不是由子類繼承..

由於內部類在頂級類的內部是可訪問的,因此它的可訪問類和子類不在封閉類中。 現在規範並沒有說明這是怎麼發生的 - 這不是真正的規範工作。給實現程序員以實現它,並且這些細節沒有記錄在當前的規範中。