有了這樣一個問題,SCJP考試正在評估你所知的隱藏。審查員故意將事情複雜化,試圖讓你相信程序的行爲只依賴於多態,而事實並非如此。
讓我們試着讓事情更清晰一些,因爲我們刪除了addFive()
方法。
class Foo {
public int a = 3;
}
class Bar extends Foo {
public int a = 8;
}
public class TestClass {
public static void main(String[]args) {
Foo f = new Bar();
System.out.println(f.a);
}
}
現在事情有點混亂。main
方法聲明類型Foo
的變量,該變量在運行時分配了類型爲Bar
的對象。這是可能的,因爲Bar
繼承自Foo
。然後程序參考Foo
類型的變量的公共字段a
。
這裏的錯誤應該是相信被稱爲的同一種概念覆蓋適用於類字段。但有沒有這樣的字段的一個概念:公共領域Bar
類的a
不壓倒一切Foo
類的公共領域a
但它確實是所謂隱藏。顧名思義,這意味着在Bar
,a
等級範圍內的Bar
自己的領域與Foo
無關。 (JLS 8.4.8 - Inheritance, Overriding, and Hiding)
那麼,當我們在寫f.a
時,我們所指的是a
?回想一下,a
字段的解析是在編譯時間完成的,使用對象f
的聲明類型,即Foo
。結果,程序打印'3'。
現在,讓我們在類Foo
中添加addFive()
方法,並在類Bar
中覆蓋它,如同考試題。這裏應用了多態性,因此調用f.addFive()
時不是使用編譯時間,而是使用對象f
的運行時類型,即Bar
來解析,因此打印爲'b'。
但是還有一點我們必須明白:爲什麼字段a
增加了5個單位,仍然堅持值'3'?這裏隱藏正在玩耍。因爲這是所謂的Bar
類的方法,並且因爲在類Bar
中,每個a
指的是Bar
的公共字段a
,所以這實際上是Bar
字段,該字段遞增。
1)現在,一個補充問題:我們怎麼可能從main
方法訪問Bar
的公共領域a
?我們能做到這一點的東西,如:
System.out.println(((Bar)f).a);
迫使編譯器來解決字段成員a
f
爲Bar
的a
場。
這將在我們的示例中打印'b 13'。
2)另一個問題:我們如何能夠解決躲在在Bar
類addFive()
方法不是指Bar
的a
領域,但其超eponimous場?就在現場參考的前面加上super
關鍵字的伎倆:
public void addFive() {
super.a += 5;
System.out.print("b ");
}
這將在我們的例子打印「B 8」。
注意,最初的聲明
public void addFive() {
this.a += 5;
System.out.print("b ");
}
可以細化到
,因爲當編譯器解析領域a
,它將開始在最接近的封閉範圍看,從內方法addFive()
,並找到Bar
類的實例,無需使用明確地this
。
但是,嗯,this
大概爲考生解決這個試題的線索!
這是一個關於SCJP的問題,對不對? – 2012-08-15 17:58:10
yep @PrakharMohan你是否也出現過相同的?我還沒有... :) – 2012-08-15 18:00:10