2013-05-21 154 views
1

在這樣的情況:多態性和繼承

class A{ 
    public int x = 4; 
    public void s3(){ 
     x = 3; 
    } 
    public void f(){ 
     x = 8; 
     s3(); 
    } 
} 

class B extends A{ 
    public int x = 5; 
    public void f(){ 
     x = 10; 
     s3(); 
    } 
} 

A a = new B(); 
B b = (B) a; 
a.f(); 
System.out.println(b.x); 
System.out.println(a.x); 

a.f()調用類B,然後f()f(),轉讓後,調用s3()功能。此時,s3()僅在A中定義,當它將值3分配給x時,xA類擁有的變量的副本。爲什麼s3()不使用B中聲明的x?理論上,B不應該有自己的副本s3()函數繼承自A? (所以s3()A繼承了B應該使用B宣佈x

+3

爲了將來的參考,對所有變量,方法和類名使用單個字符作爲名稱會使代碼難以遵循。 –

+0

「爲什麼's3()'不使用'B'中聲明的'x'?爲此'B'應該重寫's3()',這與繼承不同。 –

回答

5

你有什麼,你應該在繼承做一個誤區。 extends是明智選擇的保留字。 B擴展A的意思是說B是附加屬性的A的子集。你不應該重新定義B中的x; A應該處理x。通過在子類中重新定義x,您隱藏了父類的字段x(即使x引用了不同的變量類型,情況也是如此)。從印刷B的X,被分配到10的a.f()通話,然後調用s3()這是

A a = new B(); 
System.out.println(a.x); //4 makes sense, since we are of class A 
B b = (B) a; 
System.out.println(b.x); //5 makes sense, since we are of class B 
a.f(); 
System.out.println(a.x); //3 makes sense, since a.f() calls s3(), which sets A's x to 3 
System.out.println(b.x); //10 

的10遵循爲什麼第三個例子打印3.要明白我的意思看這個:

public void f() 
    { 
     x = 10; //sets B's x to 10 
     s3(); //calls A's s3(), which sets A's x to 3. 
    } 
+0

如果他不能重新定義B中X那麼什麼是可變的陰影..據我知道.... 公共類基地{ 公共字符串名稱=「基地」; public String getName(){return name; }} 公共類子延伸基地{ 公共字符串名稱= 「子」; public String getName(){return name; } } 這是可變的陰影 – argentum47

+0

我編輯了我的答案,包括一個關於發生了什麼的解釋。 –

+0

我看到它,只要你編輯它:) – argentum47

0

因爲它是一樣的。您沒有對象的兩個副本(「實例」),只有一個。

由於您創建的是B實例(new B()),因此將使用B中定義的方法。當然,在B中沒有定義方法時,它將使用超類方法實現。

所以,你只有一個x屬性和s3強制它是3。它工作正常。

0

爲什麼s3()不使用B中聲明的x?

通常,父類中的方法無法在子類中看到成員變量。

我想正是這樣做的:

B b = new B(); 
b.f(); 

足以重現你的困惑至少一部分。這裏是長什麼樣F()像B:

class B extends A{ 
    public int x = 5; 
    public void f(){ 
     x = 10; 
     s3(); 
    } 
} 

f()是等價於:

public void f(){ 
     this.x = 10; 
     this.s3(); 
    } 

所以調用灣f()表示f()相當於:

public void f(){ 
     b.x = 10; 
     b.s3(); 
    } 

接下來,在A的s3()方法內發生了什麼? S3()看起來是這樣的:

public void s3(){ 
     x = 3; 
    } 

,這是等同於:

public void s3(){ 
     this.x = 3; 
    } 

「這」是調用的方法,對象從f的最後一個例子(),你可以看到爲B。所以s3()相當於:

public void s3(){ 
     b.x = 3; 
    } 

所以b.x會被3 ... uhhhhm覆蓋不太快! B的一個實例也從A繼承了一個x,它只是在B的內部,所以發生了B的x 陰影來自A的x。結果,B中的f()方法分配給x的x B.在s3()裏面,然而,從A得到的x不再被遮蔽,就A而言,只有一個x--來自A的x。換句話說,對bx的查找需要一個不同的路徑取決於什麼類的語句中出現。

S3()之後執行,最終的結果是,b有兩個X有兩個不同的值。在B中的內部方法中,B中的x將是可見的,並且A中的內部方法中,A中的x將是可見的。在B中的內部方法中,可以通過使用super得到A的x。

從理論上講,B不應該有自己從s繼承的s3()函數副本?

不要以爲在副本方面。考慮從類到類的指針以及從類到查找表的指針。通常在計算機編程中,每個實例都有自己的實例變量,但方法由類中的所有實例共享。