[英]Polymorphism and inheritance
在這種情況下:
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);
af()
調用f()
類的B
,然后f()
,分配后,調用s3()
函數。 此時, s3()
僅在A
定義,並且當它向x
賦值3時, x
是類A
擁有的變量的副本。 為什么s3()
不使用B
聲明的x
? 從理論上講, B
不應該擁有從A
繼承的s3()
函數的副本嗎? (因此從B
A
繼承的s3()
應該使用B
聲明的x
)
您對繼承中的操作有誤解。 extends
是一個明智選擇的保留字。 B擴展A的要點是說B是具有附加屬性的A的子集。 您不應該在B中重新定義x
; A應該處理x
。 通過在子類中重新定義x
,您可以隱藏超類的字段x
(即使x
引用了不同的變量類型,也是如此)。
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之后是打印b的x,通過調用af()
將其分配給10,然后調用s3()
,這就是第三個示例打印3的原因。要了解我的意思,請看以下內容:
public void f()
{
x = 10; //sets B's x to 10
s3(); //calls A's s3(), which sets A's x to 3.
}
因為是一樣的。 您沒有該對象的兩個副本(“實例”),只有一個。
由於您創建的實例是一個B
實例( new B()
),因此將使用B
定義的方法。 當然,如果在B
中未定義任何方法,它將使用超類方法實現。
因此,您只有一個x
屬性,而s3
則將其強制為3
。 可以。
為什么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();
}
因此,調用bf()意味着f()等效於:
public void f(){
b.x = 10;
b.s3();
}
接下來,在A的s3()方法內部會發生什么? s3()看起來像這樣:
public void s3(){
x = 3;
}
等效於:
public void s3(){
this.x = 3;
}
“ this”是調用該方法的對象,在上一個f()示例中,您可以看到它是b。 因此s3()等效於:
public void s3(){
b.x = 3;
}
所以bx很快就被3 ...覆蓋了!
B的實例也繼承了A的x,只是B內的x碰巧B的x 遮蔽了A的x。結果,B中的f()方法將B的x賦給了x。內部s3()但是,從a獲得的b的x不再被遮蔽了,就A而言,只有一個x-來自A的x。換句話說,對bx的查找取決於該類是什么而不同語句出現在。
執行s3()之后,最終結果是b具有兩個帶有兩個不同值的x。 在B的方法內部,來自B的x將是可見的,而在A的方法內部,來自A的x將是可見的。 在B的內部方法中,可以使用super從A處獲得x。
從理論上講,B不應該擁有從A繼承來的s3()函數的副本嗎?
不要以副本來思考。 考慮從類到類的指針,以及從類到查找表的指針。 通常在計算機編程中,每個實例都有其自己的實例變量,但是方法由類中的所有實例共享。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.