封裝、繼承、多態(tài)是面向?qū)ο缶幊讨腥齻€(gè)比較重要的概念,理解這3個(gè)概念對領(lǐng)會(huì)JAVA語言至關(guān)重要,而搞懂方法的覆蓋又是理解繼承的關(guān)鍵部分,這里主要看一下靜態(tài)方法的覆蓋。
首先看一段代碼:
運(yùn)行Test 類的結(jié)果為:Good night,Dick
也許你會(huì)感到迷惑,這里調(diào)用的到底是Super類的方法還是Sub子類的方法?讓我們首先判斷調(diào)用的是哪個(gè)類的name()方法。兩個(gè)類中的name()方法都不是靜態(tài)方法而是實(shí)例方法,因?yàn)镾ub 類繼承了Super 類而且有一個(gè)和它父類同樣標(biāo)識的name()方法,所以Sub 類中的name()方法覆蓋了Super 類中的name()方法,那么前面提到的變量s 又是Sub 類的一個(gè)實(shí)例,這樣一來s.name()的返回值就是Dick 了。
至此我們解決了問題的一半,現(xiàn)在我們需要判斷被調(diào)用的greeting()方法究竟是Super類的還是Sub 類的。需要注意的是,兩個(gè)類中的greeting()方法都是靜態(tài)方法,也稱為類方法。盡管事實(shí)上Sub 類的greeting()方法具有相同的返回類型、相同的方法名以及相同的方法參數(shù),然而它并不覆蓋Super 類的greeting()方法。由于變量s 被強(qiáng)制轉(zhuǎn)換為Super 型并且Sub 類的greeting()方法沒有覆蓋Super 類的greeting()方法,因此s.greeting()的返回值為Goodnight 。還是很迷惑?請記住這條規(guī)則:“實(shí)例方法被覆蓋,靜態(tài)方法被隱藏” 。假如你就是剛才大喊不能覆蓋靜態(tài)方法的讀者之一,那么你完全正確?,F(xiàn)在你可能會(huì)問:“隱藏和覆蓋有什么區(qū)別”?你也許還未理解這點(diǎn),然而實(shí)際上我們剛剛在這個(gè)Super/Sub 類的例子中已經(jīng)解釋了兩者的不同。使用類的全局名可以訪問被隱藏的方法,即使變量s 是Sub 類的一個(gè)實(shí)例,而且Sub 類的greeting()方法隱藏了Super 類的同名方法,我們?nèi)耘f能夠?qū) 強(qiáng)制轉(zhuǎn)換為Super 型以便訪問被隱藏的greeting()方法。與被隱藏的方法不同,對被覆蓋的方法而言,除了覆蓋它們的類之外其他任何類都無法訪問它們,這就是為何變量s 調(diào)用的是Sub 類的而非Super 類的name()方法。
本單元簡要解釋了Java 語言中一個(gè)不時(shí)引起混淆的問題,也許對你來說理解隱藏靜態(tài)方法和覆蓋實(shí)例方法的區(qū)別的最佳方式就是自己創(chuàng)建幾個(gè)類似于Sub/Super 的類再重復(fù)一次規(guī)則“實(shí)例方法被覆蓋而靜態(tài)方法被隱藏”,被覆蓋的方法只有覆蓋它們的類才能訪問它們,而訪問被隱藏的方法的途徑是提供該方法的全局名。
現(xiàn)在你終于明白標(biāo)題里問題的答案了吧?什么時(shí)候“被覆蓋的”方法并非真地被覆蓋了呢?答案就是“永遠(yuǎn)不會(huì)”。另外,還有幾點(diǎn)要注意:
1. 試圖用子類的靜態(tài)方法隱藏父類中同樣標(biāo)識的實(shí)例方法是不合法的,編譯器將會(huì)報(bào)
錯(cuò);
2. 試圖用子類的實(shí)例方法覆蓋父類中同樣標(biāo)識的靜態(tài)方法也是不合法的,編譯器同樣
會(huì)報(bào)錯(cuò);
3. 靜態(tài)方法和最終方法(帶關(guān)鍵字final 的方法)不能被覆蓋;
4. 實(shí)例方法能夠被覆蓋;
5. 抽象方法必須在具體類中被覆蓋