重新定義實作

文章推薦指數: 80 %
投票人數:10人

對 drawFight() 方法而言,只知道傳進來的會是一種 Role 物件,所以編譯器也只能檢查你呼叫的方法, Role 是不是有定義,顯然地, Role 目前並沒有定義 fight() 方法, ... 回Java目錄 現在有個需求,請設計static方法,可以播放角色攻擊動畫,你也許會這麼想,學剛剛多型的寫法,設計個drawFight()方法如何? 對drawFight()方法而言,只知道傳進來的會是一種Role物件,所以編譯器也只能檢查你呼叫的方法,Role是不是有定義,顯然地,Role目前並沒有定義fight()方法,因此編譯錯誤了。

然而你仔細觀察一下SwordsMan與Magician的fight()方法,他們的方法簽署(methodsignature)都是: publicvoidfight() 也就是說,操作介面是相同的,只是方法實作內容不同,你可以將fight()方法提昇至Role類別中定義: packagecc.openhome; publicclassRole{ ...略 publicvoidfight(){ //子類別要重新定義fight()的實際行為 } } 在Role類別中定義了fight()方法,由於實際上角色如何攻擊,只有子類別才知道,所以這邊的fight()方法內容是空的,沒有任何程式碼實作。

SwordsMan繼承Role之後,再對fight()的實作進行定義: packagecc.openhome; publicclassSwordsManextendsRole{ publicvoidfight(){ System.out.println("揮劍攻擊"); } } 在繼承父類別之後,定義與父類別中相同的方法簽署,但實作內容不同,這稱為重新定義(Override),因為對父類別中已定義的方法實作不滿意,所以你在子類別中重新定義實作。

Magician繼承Role之後,也重新定義了fight()的行為: packagecc.openhome; publicclassMagicianextendsRole{ publicvoidfight(){ System.out.println("魔法攻擊"); } ...略 } 由於Role現在定義了fight()方法(雖然方法區塊中沒有程式碼實作),所以編譯器不會找不到Role的fight()了,因此你可以如下撰寫: packagecc.openhome; publicclassRPG{ publicstaticvoidmain(String[]args){ SwordsManswordsMan=newSwordsMan(); swordsMan.setName("Justin"); swordsMan.setLevel(1); swordsMan.setBlood(200); Magicianmagician=newMagician(); magician.setName("Monica"); magician.setLevel(1); magician.setBlood(100); drawFight(swordsMan); drawFight(magician); } staticvoiddrawFight(Rolerole){ System.out.print(role.getName()); role.fight(); } } 在fight()方法宣告了Role型態的參數,那方法中呼叫的,到底是Role中定義的fight(),還是個別子類別中定義的fight()呢?如果傳入fight()的是SwordsMan,role參數參考的就是SwordsMan實例,操作的就是SwordsMan上的方法定義。

這就好比role牌子掛在SwordsMan實例身上,你要求有role牌子的物件攻擊,發動攻擊的物件就是SwordsMan實例。

同樣地,如果傳入fight()的是Magician,role參數參考的就是Magician實例,操作的就是Magician上的方法定義。

所以範例最後的執行結果是: Justin揮劍攻擊 Monica魔法攻擊 在重新定義父類別中某個方法時,子類別必須撰寫與父類別方法中相同的簽署,然而如果疏忽打錯字了: publicclassSwordsManextendsRole{    publicvoidFight(){        System.out.println("揮劍攻擊");    } } 以這邊的例子來說,父類別中定義的是fight(),但子類別中定義了Fight(),這就不是重新定義fight()了,而是子類別新定義了一個Fight()方法,這是合法的方法定義,編譯器並不會發出任何錯誤訊息,你只會在運行範例時,發現為什麼SwordsMan完全沒有攻擊。

在JDK5之後支援標註(Annotation),其中一個內建的標準標註就是@Override,如果你在子類別中某個方法前標註@Override,表示要求編譯器檢查,該方法是不是真的重新定義了父類別中某個方法,如果不是的話,就會引發編譯錯誤。

例如:



請為這篇文章評分?