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