方法重寫:子類如何“修改”父類的方法?¶
在Java中,當我們創建子類繼承父類時,有時需要對父類的方法進行“個性化修改”——這就是方法重寫(Override)。簡單來說,方法重寫就是子類根據自身需求,在保留方法聲明(名稱、參數等)不變的前提下,重新編寫方法的具體實現。
爲什麼需要方法重寫?¶
想象一下:如果父類定義了一個通用的“動物喫飯”方法,子類“狗”和“貓”雖然都是動物,但喫飯的行爲不同(狗喫骨頭,貓喫魚)。直接使用父類方法顯然不符合子類的需求,而方法重寫能讓子類靈活地修改這個方法的內容,同時保持方法聲明的一致性。
方法重寫的“規則”(必須滿足的條件)¶
要正確實現方法重寫,需要滿足以下規則(缺一不可):
-
方法名和參數列表必須完全相同
子類方法的名稱、參數的數量、類型、順序必須與父類方法一致。例如:父類eat()方法的參數是(),子類重寫時也必須是eat()。 -
返回值類型“協變”
子類方法的返回值類型可以是父類方法返回值類型本身,或者是它的“子類類型”(例如:父類返回Object,子類返回String;父類返回Animal,子類返回Dog)。 -
訪問權限不能更嚴格
子類方法的訪問權限必須大於或等於父類方法。例如:父類方法是public,子類可以是public或protected;父類是protected,子類不能寫成private(權限縮小會導致編譯錯誤)。 -
異常處理更寬鬆
子類方法拋出的異常必須是父類方法拋出異常的“子類”或更少異常(不能拋出比父類更多或更寬泛的異常)。
舉個例子:動物喫飯的重寫¶
我們用代碼直觀感受方法重寫:
// 父類:動物類
class Animal {
// 父類的方法:喫飯(通用實現)
public void eat() {
System.out.println("動物喫飯");
}
}
// 子類:狗類(繼承Animal)
class Dog extends Animal {
// 重寫父類的eat()方法
@Override
public void eat() {
System.out.println("狗喫骨頭!");
}
}
// 子類:貓類(繼承Animal)
class Cat extends Animal {
// 重寫父類的eat()方法
@Override
public void eat() {
System.out.println("貓喫魚!");
}
}
// 測試類
public class TestOverride {
public static void main(String[] args) {
Dog dog = new Dog();
Cat cat = new Cat();
dog.eat(); // 輸出:狗喫骨頭!
cat.eat(); // 輸出:貓喫魚!
}
}
關鍵點:@Override 註解是可選的,但加上後編譯器會幫我們檢查是否真的滿足重寫規則(例如方法名拼寫錯誤會報錯),建議養成習慣。
方法重寫與“多態”的關係¶
方法重寫是多態(Polymorphism)的核心基礎,尤其是“運行時多態”(動態綁定)。當父類引用指向子類對象時,調用重寫的方法會自動執行子類的實現。
// 父類引用指向子類對象
Animal a = new Dog();
a.eat(); // 輸出:狗喫骨頭!(執行子類的重寫方法)
a = new Cat();
a.eat(); // 輸出:貓喫魚!(執行子類的重寫方法)
這裏 a 是 Animal 類型的引用,但實際指向 Dog 或 Cat 對象,調用 eat() 時會根據對象的實際類型(子類)執行對應的方法——這就是“多態”的體現。
方法重寫 vs 方法重載(別搞混!)¶
初學者容易混淆方法重寫和方法重載(Overload),兩者的區別如下:
| 對比項 | 方法重寫(Override) | 方法重載(Overload) |
|---|---|---|
| 發生場景 | 子類對父類的方法進行修改 | 同一類中方法名相同,參數不同 |
| 核心目標 | 擴展/修改父類行爲,實現多態 | 同一功能的不同參數版本(參數列表不同) |
| 規則 | 名稱、參數列表、返回值需一致 | 名稱相同,參數列表(數量/類型/順序)不同 |
總結¶
方法重寫是Java中實現代碼複用和擴展的重要機制,它讓子類既能繼承父類的“框架”,又能根據自身需求修改“細節”。同時,方法重寫是多態的核心基礎——通過父類引用指向子類對象,程序能在運行時自動選擇正確的方法實現,大幅提升代碼的靈活性和可擴展性。
小練習:嘗試定義一個 Bird 類繼承 Animal,重寫 eat() 方法輸出“鳥喫蟲子”,然後用多態方式測試!