Java方法重寫:子類覆蓋父類方法,實現多態基礎

方法重寫:子類如何“修改”父類的方法?

在Java中,當我們創建子類繼承父類時,有時需要對父類的方法進行“個性化修改”——這就是方法重寫(Override)。簡單來說,方法重寫就是子類根據自身需求,在保留方法聲明(名稱、參數等)不變的前提下,重新編寫方法的具體實現。

爲什麼需要方法重寫?

想象一下:如果父類定義了一個通用的“動物喫飯”方法,子類“狗”和“貓”雖然都是動物,但喫飯的行爲不同(狗喫骨頭,貓喫魚)。直接使用父類方法顯然不符合子類的需求,而方法重寫能讓子類靈活地修改這個方法的內容,同時保持方法聲明的一致性。

方法重寫的“規則”(必須滿足的條件)

要正確實現方法重寫,需要滿足以下規則(缺一不可):

  1. 方法名和參數列表必須完全相同
    子類方法的名稱、參數的數量、類型、順序必須與父類方法一致。例如:父類 eat() 方法的參數是 (),子類重寫時也必須是 eat()

  2. 返回值類型“協變”
    子類方法的返回值類型可以是父類方法返回值類型本身,或者是它的“子類類型”(例如:父類返回 Object,子類返回 String;父類返回 Animal,子類返回 Dog)。

  3. 訪問權限不能更嚴格
    子類方法的訪問權限必須大於或等於父類方法。例如:父類方法是 public,子類可以是 publicprotected;父類是 protected,子類不能寫成 private(權限縮小會導致編譯錯誤)。

  4. 異常處理更寬鬆
    子類方法拋出的異常必須是父類方法拋出異常的“子類”或更少異常(不能拋出比父類更多或更寬泛的異常)。

舉個例子:動物喫飯的重寫

我們用代碼直觀感受方法重寫:

// 父類:動物類
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(); // 輸出:貓喫魚!(執行子類的重寫方法)

這裏 aAnimal 類型的引用,但實際指向 DogCat 對象,調用 eat() 時會根據對象的實際類型(子類)執行對應的方法——這就是“多態”的體現。

方法重寫 vs 方法重載(別搞混!)

初學者容易混淆方法重寫方法重載(Overload),兩者的區別如下:

對比項 方法重寫(Override) 方法重載(Overload)
發生場景 子類對父類的方法進行修改 同一類中方法名相同,參數不同
核心目標 擴展/修改父類行爲,實現多態 同一功能的不同參數版本(參數列表不同)
規則 名稱、參數列表、返回值需一致 名稱相同,參數列表(數量/類型/順序)不同

總結

方法重寫是Java中實現代碼複用和擴展的重要機制,它讓子類既能繼承父類的“框架”,又能根據自身需求修改“細節”。同時,方法重寫是多態的核心基礎——通過父類引用指向子類對象,程序能在運行時自動選擇正確的方法實現,大幅提升代碼的靈活性和可擴展性。

小練習:嘗試定義一個 Bird 類繼承 Animal,重寫 eat() 方法輸出“鳥喫蟲子”,然後用多態方式測試!

小夜