2009-12-16 67 views
1

考慮一下:爲什麼不根據其對象的運行時類型選擇此方法?

class A { 
    int x =5; 
} 

class B extends A{ 
     int x =6; 
    } 
public class CovariantTest { 

    public A getObject() { 
     return new A(); 
    } 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     // TODO code application logic here 
     CovariantTest c1 = new SubCovariantTest(); 
     System.out.println(c1.getObject().x); 
    } 

} 

class SubCovariantTest extends CovariantTest { 
    public B getObject(){ 
     return new B(); 
    } 
} 

據我所知,JVM選擇基礎上的真實類型的對象的方法。這裏的真正類型是SubCovariantTest,它定義了一個覆蓋方法getObject。

該程序打印5,而不是6.爲什麼?

回答

10

該方法確實是由對象的運行時類型選擇的。運行時類型未選擇的是整數字段x。對於B對象存在x的兩個副本,一個用於A.x,另一個用於B.x。您是靜態A類中選擇字段,因爲編譯時getObject返回的對象的類型是A。這個事實可以通過添加的方法進行驗證,以AB

class A { 
    public String print() { 
     return "A"; 
    } 
} 

class B extends A { 
    public String print() { 
     return "B"; 
    } 
} 

和改變測試表達式:

System.out.println(c1.getObject().print()); 
+0

你做了解釋它比我...它實際上樣的一個棘手的一個字一個更好的工作...... – LorenVS 2009-12-17 00:06:13

1

除非我記錯了,方法是在默認情況下,Java虛擬,所以你正在重寫該方法。然而,字段(如'x')不是虛擬的,不能被重寫。當你在B中聲明「int x」時,你實際上是在創建一個全新的變量。

多態性不會對字段生效,所以當您嘗試檢索類型爲A的對象上的x時,您將得到5,如果對象被轉換爲類型B,則會得到6.

1

當super和子類中的字段具有相同的名稱時,它被稱爲「隱藏」。除了在答問中提到的問題,還有其他方面可能以微妙的問題引起:

http://java.sun.com/docs/books/tutorial/java/IandI/hidevariables.html

在一類,具有 相同的名稱作爲一個字段的字段超類 隱藏超類的字段,即使它們的類型不同 也是如此。在 子類中,超類 中的字段不能被其簡單的 名稱引用。相反,該字段必須是 通過超級訪問,這是在下一節中討論的 。一般來說 來說,我們不建議隱藏 字段,因爲它使代碼難以讀取到 。

一些編譯器會警告不要隱藏變量

相關問題