2011-09-11 110 views
3

我定義三個類(A,B,C):爪哇不清楚結果

public class A { 
    int i = 5; 
    public A() { 
     foo(); 
    } 
    public void foo() { 
     System.out.println(i); 
    } 
} 

class B extends A { 
    int i = 6; 
} 

class C extends B { 
     int i = 7; 
    public void foo() { 
     System.out.print(super.i); 
    } 
    public static void main(String[] args) { 
     C c = new C(); 
    } 
} 

預期的結果是:6 但程序返回:0

有人可以解釋的結果? 您的幫助將不勝感激。

回答

5

類別C覆蓋A.foo(),即使在Java中的構造函數中多態也是活動的。因此,當我們構建C的實例時,A中的構造函數調用foo()時,實際上會調用它的C.foo()

C.foo()轉而打印出B.i,所以我們可能會預計6被打印出來 - 但實例變量初始化後超類的構造函數只執行,所以在執行的角度來看,B.i爲0

基本上,一個構造的執行順序是:

  • 執行鏈式構造,無論是明確地this(...)到鏈到另一或者顯式地將super(...)鏈接到超類中的構造函數,或者隱式地將super()鏈接到超類中的無參數構造函數。
  • 對於鏈接到超類構造函數的構造函數,執行變量初始值設定項。
  • 在構造體

執行代碼重寫代碼以避免使用變量初始化和可變遮蔽使得該清晰,同時仍保持代碼當量:

public class A { 
    int ai; 

    public A() { 
    super(); 
    ai = 5; 
    foo(); 
    } 

    public void foo() { 
    System.out.println(ai); 
    } 
} 

class B extends A { 
    int bi; 

    public B() { 
    super(); 
    bi = 6; 
    } 
} 

class C extends B { 
    int ci; 

    public C() { 
    super(); 
    ci = 7; 
    } 

    public void foo() { 
    System.out.print(bi); 
    } 

    public static void main(String[] args) { 
    C c = new C(); 
    } 
} 

順便說一句,該「隱藏變量」的一部分不會發揮作用,如果你讓所有的字段都是私有的,那麼我建議這麼做。這就留下了從構造函數調用虛擬方法的問題,這通常是一個糟糕的主意,因爲期望對象能夠在它有機會完全初始化之前工作,以及變量初始化器執行可能令人驚訝的時機。

如果您避免從構造函數調用虛擬方法,即使變量初始值設定項的時間變得無關緊要 - 至少幾乎總是

1

這個變量在類A中永遠不會被初始化,因此它會打印默認變量爲0的初始狀態。事情是,雖然超級被調用了層次結構樹上的構造函數,但構造函數並沒有初始化i ,這是在初始化完成的,這發生在構造函數之後。

+0

後不構造 - 但編譯構造體的第一部分* *後調用父類的構造。 –

0

我不確定你的期望 - 你的示例不會按原樣運行,並且如果運行的話它將不會執行任何操作。

本例返回「6」:

public class A { 
    int i = 5; 
    public A() { 
     foo(); 
    } 
    public void foo() { 
     System.out.println(i); 
    } 
    public static void main(String[] args) { 
     C c = new C(); 
     c.foo(); 
    } 
} 

class B extends A { 
    int i = 6; 
} 

class C extends B { 
    int i = 7; 
    public void foo() { 
     System.out.print(super.i); 
    } 
} 
+0

OP的代碼編譯和運行對我來說非常好,並打印0.您的代碼打印06 - 從構造函數打印0調用'foo()'。它只是在構造函數之後調用'foo()'*打印6。 –