Overriding(覆寫/重寫)與 Overloading(多載/重載)是 Java 多型機制的兩大支柱,雖名稱相似但語意截然不同。本文系統整理兩者規則、差異與實務陷阱。
覆寫發生於繼承體系中,子類別對父類別非私有方法提供新實作。典型場景:實作介面方法、覆寫父類別具體方法。
protected 可覆寫為 public,不可改為 privateIOException,子可拋 IOException 或其子類,不可拋 Exception// 父類別
protected void do(int i, double d) throws IOException { }
// 合法覆寫
public void do(int i, double d) throws IOException { }
public void do(int i, double d) throws FileNotFoundException { } // 子類異常
// 非法覆寫
private void do(int i, double d) { } // 權限縮減
public void do(int i, double d) throws Exception { } // 異常範圍擴大
多載發生於同一類別(或子類別繼承父類別多載方法),透過參數差異區分呼叫目標。編譯期靜態綁定。
「Two or more methods can have the same name if they have different numbers or types of parameters and thus different signatures.」
唯一硬性要求:參數列表必須改變。
當找不到完全匹配的多載方法時,Java 會嘗試自動型別轉換(Widening Primitive Conversion)尋找最匹配的簽名:
class OverloadDemo {
void test() { System.out.println("No parameters"); }
void test(int a, int b) { System.out.println("a and b: " + a + " " + b); }
void test(double a) { System.out.println("Inside test(double) a: " + a); }
}
public class Overload {
public static void main(String[] args) {
OverloadDemo ob = new OverloadDemo();
int i = 88;
ob.test(); // 呼叫 test()
ob.test(10, 20); // 呼叫 test(int, int)
ob.test(i); // int → double,呼叫 test(double)
ob.test(123.2); // 呼叫 test(double)
}
}
輸出:
No parameters
a and b: 10 20
Inside test(double) a: 88
Inside test(double) a: 123.2
關鍵規則: 若定義 test(int),則 ob.test(i) 會優先匹配 test(int) 而非轉型至 test(double)。自動轉換僅在找不到精確匹配時啟動,且選擇參數型別「較大且最接近」的方法。
| 特性 | Overriding (覆寫) | Overloading (多載) |
|---|---|---|
| 發生範圍 | 父子類別之間 | 同一類別內(含繼承而來) |
| 方法簽名 | 完全相同 | 參數列表必須不同 |
| 回傳型別 | 相同/共變 | 任意 |
| 存取權限 | 不得縮減 | 無限制 |
| 檢查型異常 | 不得擴大 | 無限制 |
| 綁定時機 | 執行期(動態) | 編譯期(靜態) |
| 多型類型 | 執行期多型 | 編譯期多型 |
@Override 註解,編譯器可攔截簽名錯誤