方法重載 和方法重寫 是 Java 多型的兩大核心機制,前者為編譯時多型 (靜態綁定),後者為執行時多型 (動態綁定)。本文系統比較定義、規則、程式碼範例、常見誤區與面試重點。
| 維度 | 重載 | 重寫 |
|---|---|---|
| 發生範圍 | 同一個類別內 | 父子類別之間 |
| 方法名稱 | 相同 | 相同 |
| 參數列表 | 必須不同 (型別、個數、順序) | 必須相同 |
| 回傳型別 | 可相同可不同 | 相同或為子型別 (協變) |
| 存取修飾符 | 無限制 | 不能比父類別更嚴格 (public > protected > default > private) |
| 拋出異常 | 無限制 | 不能拋出父類別未宣告的受檢異常 |
| 綁定時間 | 編譯期 (靜態) | 執行期 (動態) |
| 關鍵字 | 無 (可選 @Override 不適用) | 建議加 @Override |
| 別名 | Overload | Override / 覆蓋 |
public class Calculator {
// 1. 參數個數不同
public int add(int a, int b) { return a + b; }
public int add(int a, int b, int c) { return a + b + c; }
// 2. 參數型別不同
public double add(double a, double b) { return a + b; }
// 3. 參數順序不同 (罕見但合法)
public String concat(String s, int n) { return s + n; }
public String concat(int n, String s) { return n + s; }
// ❌ 僅回傳型別不同 -> 編譯錯誤
// public long add(int a, int b) { return a + b; }
}
構造函數重載 是最常見應用:new User(), new User(name), new User(name, age)。
class Animal {
public void move() { System.out.println("Animal moves"); }
protected void breathe() { System.out.println("Breathing"); }
}
class Bird extends Animal {
@Override
public void move() { // 重寫:public -> public,參數相同
System.out.println("Bird flies");
}
@Override
protected void breathe() { // protected -> protected
super.breathe(); // 可選:呼叫父類別實作
System.out.println("Bird breathing fast");
}
// ❌ private 方法不可被重寫 (父類別若為 private,子類別定義同名方法屬於新方法)
// ❌ final 方法不可被重寫
// ❌ static 方法不可被重寫 (屬於隱藏)
}
| 誤區 | 正確說明 |
|---|---|
| 「重載看回傳型別」 | 重載完全不看回傳型別,只看參數列表。僅回傳型別不同會編譯錯誤。 |
| 「static 方法可以重寫」 | static 方法屬於類別,不屬於實例,無法重寫,只能隱藏。呼叫時靜態綁定至宣告型別。 |
| 「private 方法可以重寫」 | private 方法對子類別不可見,子類別定義同名方法是新方法,非重寫。@Override 會報錯。 |
| 「建構子可以重寫」 | 建構子不被繼承,無法重寫。子類別必須自行定義建構子並呼叫 super(...)。 |
| 「重寫方法拋出更多異常」 | 重寫方法不能拋出父類別未宣告的受檢異常,但可拋出較少、較具體、或非受檢異常。 |
| 「重載需在不同類別」 | 重載發生在同一個類別內 (含繼承來的方法)。 |
class Parent {
public void show() { System.out.println("Parent"); }
public static void staticShow() { System.out.println("Parent static"); }
}
class Child extends Parent {
@Override
public void show() { System.out.println("Child"); }
public static void staticShow() { System.out.println("Child static"); } // 隱藏
}
public class Test {
public static void main(String[] args) {
Parent p = new Child();
p.show(); // 輸出 Child (動態綁定,重寫)
p.staticShow(); // 輸出 Parent static (靜態綁定,隱藏)
((Child) p).staticShow(); // 輸出 Child static
}
}
@Override 註解的作用 (編譯器檢查是否真正重寫,防止拼寫錯誤)。