2015-09-07 77 views
3

示例代碼:瞭解Java的繼承模型

public class Parent { 
    String name = "Parent"; 

    public String getName() { 
    return this.name; 
    } 
} 

public class Child extends Parent { 
    String name = "Child"; 

    public String getName() { 
    return this.name; 
    } 
} 

public class Tester { 
    public static void main (String[] args) { 
    Parent p = new Child(); 
    Child c = new Child(); 
    System.out.println("p.name is " + p.name); // prints out "Parent" 
    System.out.println("c.name is " + c.name); // prints out "Child" 
    System.out.println("p.getName() is " + p.getName()); // prints out "Child" 
    System.out.println("c.getName() is " + c.getName()); // prints out "Child" 
    } 
} 

我的理解到目前爲止

到目前爲止,我在Java繼承的理解讓我明白爲什麼第3和第4 println語句產生「兒童「作爲輸出。在編譯時,編譯器確保getName方法在參考變量的類型中定義,但在運行期間是確定哪個版本的getName。並且因爲兩個參考變量實際上指的是一個Child對象,所以調用了兒童的getName

問題1

但是,爲什麼當你直接訪問實例變量,該行爲是由方法是如何被訪問的有什麼不同?特別是,我發現奇怪的是p.name返回「Parent」而不是「Child」。

問題2

與此類似,如果我在Child類註釋掉getName功能和Tester重新運行的代碼,我很驚訝地看到,p.getName()c.getName()回報「父母「而不是」孩子「。

有人可以幫助解釋這2個問題嗎?

+2

你所做的全部問題是你認爲你可以覆蓋變量,但是你不能。檢查[這](http://stackoverflow.com/questions/7794621/hiding-instance-variables-of-a-class) – SomeJavaGuy

+1

感謝您分享此鏈接@KevinEsche!這是如何適用於我的第二個問題? – wmock

+0

另外,繼承描述了*是a *關係。出於這個原因,「家長」/「孩子」的比喻非常糟糕。 「孩子」不是*「父母」。 – aioobe

回答

4

變量不能在Java中重寫。你做了什麼叫做躲在一個變量(在Parent變量name很難進入)

瞭解您所描述的行爲方式是想name變量作爲唯一的名稱,而不是實際的變量。當在上下文中使用(在代碼中,而不是實際變量類型)Parent時,它指向的變量與在Child的上下文中使用的變量不同。

當調用c.namep.name你告訴程序使用的情況下,因爲變量cp分別宣佈Child類型和Parent的。在類中的方法中使用它時,將使用當前類的變量。

如果你想在一個子類使用Parent.name你將不得不投它:

System.out.println("c.name is " + ((Parent) c).name); 

一種方法,調用該函數始終是實際的變量類型的被調用。在你的情況下,不管從TesterParentClient打電話。

當然,最好不要隱藏變量,對不同的變量使用不同的名稱。

+0

謝謝澄清@Thirler - 這對我來說現在是有意義的。 – wmock