[英]Explain how variable hiding is working in this Java code
考慮下面的代碼
class A
{
int x = 5;
void foo()
{
System.out.println(this.x);
}
}
class B extends A
{
int x = 6;
// some extra stuff
}
class C
{
public static void main(String args[])
{
B b = new B();
System.out.println(b.x);
System.out.println(((A)b).x);
b.foo();
}
}
該計划的輸出是
6
5
5
我理解前兩個但是無法理解最后一個。 b.foo()如何打印5.B類將繼承foo方法。 但它不應該打印bx會打印什么? 到底發生了什么?
是的, B
類繼承了foo
方法。 但是B
的變量x
隱藏了A
的x
; 它不會取代它。
這是一個范圍問題。 A
的foo
方法只能看到范圍內的變量。 范圍中唯一的變量是A
的實例變量x
。
foo
方法在B
繼承但未被覆蓋。 如果您使用相同的確切代碼顯式覆蓋foo
:
class B extends A
{
int x = 6;
@Override
void foo()
{
System.out.println(this.x);
}
}
然后該變量時提到了,這將是在范圍this.x
將B
的x
,和6
將被打印。 雖然方法的文本是相同的,但由於范圍的原因,引用是不同的。
順便提一下,如果你真的想在B
類中引用A
的x
,你可以使用super.x
。
字段在Java和具有相同字段名稱的子類中不能覆蓋父類陰影“僅”父類的字段。
所以this.x
指的是當前類中定義的x
: A
。
結果: 5
。
更確切地說: foo()
方法由B
子類繼承,但它並不意味着繼承方法的行為將因引用的實例字段而改變,因為所述字段不可覆蓋:引用的this.x
表達式foo()
方法中的Ax
字段繼續引用Ax
。
這與之前的兩個陳述完全相同:
B b = new B();
System.out.println(b.x); // refers B.x -> 6
System.out.println(((A)b).x); // refers A.x -> 5
b.foo(); // refers under the hood A.x -> 5
rgettman的非常好的答案顯示了如何克服隱藏在子類中的字段。
克服隱藏的替代方法依賴於使實例字段為private
(建議使用)並提供返回值的方法。
通過這種方式,您可以從覆蓋機制中受益,並且字段隱藏不再是類的客戶端的問題:
class A
{
private int x = 5;
int getX(){
return x;
}
void foo()
{
System.out.println(this.getX());
}
}
class B extends A
{
private int x = 6;
int getX(){
return x;
}
}
嗯,這是因為靜態綁定。
1)Java中的靜態綁定在編譯時發生,而動態綁定在運行時發生。
2)私有方法,最終方法和靜態方法和變量使用靜態綁定並由編譯器綁定,而虛擬方法在運行時基於運行時對象綁定。
3)靜態綁定使用Type(Java中的類)信息進行綁定,而動態綁定使用Object來解析綁定。
4)使用靜態綁定綁定重載方法,而在運行時使用動態綁定綁定重寫方法。
在JAVA中 ,可以覆蓋方法,而變量則不能。 因此,由於您的方法foo
未在B
被覆蓋,因此它從A
獲取成員變量。
你打電話的時候
b.foo();
它檢查B
是否覆蓋了方法foo()
,它沒有。 然后它向一個級別向上看,超類A
並調用該方法。
然后你調用了A
的foo()
版本然后打印出來
this.x
現在, A
看不到B
的x
版本。
為了解決這個問題,你必須覆蓋B
的方法
class B extends A
{
int x = 6;
@Override
void foo()
{
System.out.println(this.x);
}
}
現在,打電話
b.foo();
將調用B
的foo()
版本,您將獲得預期的結果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.