Override vs Overload:從語法規則到多態實踐
方法覆蓋(Override)實現運行時多態,方法重載(Overload)實現編譯時多態。本文系統梳理定義、規則、區別、常見錯誤與最佳實踐。
方法覆蓋(Override)
定義:子類重新定義父類非私有實例方法,簽名(方法名+參數列表)、返回類型完全一致。
鐵律:
- ✅ 訪問權限 ≥ 父類(public > protected > default > private)
- ✅ 拋出異常 ⊆ 父類(可少拋、拋子類異常,不可拋新的受檢異常)
- ❌ final 方法不可覆蓋
- ❌ private 方法不可覆蓋(子類定義同名方法屬新方法)
- ❌ static 方法不可覆蓋(靜態綁定,隱藏而非覆蓋)
- ✅ 實例方法可覆蓋,構造器不可繼承/覆蓋
- ✅ 子類調用父實現:
super.method()
方法重載(Overload)
定義:同一類(含繼承而來)中,方法名相同、參數列表不同(類型/個數/順序),返回類型/權限/異常無要求。
發生範圍:單類內 + 父子類之間(父類方法被繼承,子類可重載)。
覆蓋 vs 重載 對比表
| 維度 | 覆蓋 | 重載 |
| 參數列表 | 必須相同 | 必須不同 |
| 返回類型 | 必須相同(或協變) | 無要求 |
| 訪問權限 | 不能降低 | 無要求 |
| 拋出異常 | 不能擴大 | 無要求 |
| 綁定時機 | 運行時(動態分派) | 編譯時(靜態分派) |
| 發生位置 | 子類覆蓋父類 | 同類/父子類均可 |
| 多態類型 | 運行時多態 | 編譯時多態 |
實戰示例
class Animal {
public void say() { println("動物叫聲"); }
public void eat(String food) { println("吃 " + food); }
}
class Dog extends Animal {
// 覆蓋
@Override public void say() { println("汪汪"); }
// 重載(同類)
public void eat(String food, int amount) { println("吃 " + amount + " 份 " + food); }
// 重載(父類方法被繼承,此處構成重載)
public void eat(Food food) { println("吃食物對象"); }
}
常見陷阱
- ❌ 以為 static 方法可覆蓋 → 實為隱藏,父類引用調用仍執行父類版本
- ❌ 覆蓋時縮小訪問權限(protected → default) → 編譯錯誤
- ❌ 覆蓋時新增受檢異常 → 編譯錯誤
- ❌ 構造器嘗試覆蓋 → 構造器不參與繼承
- ✅ 加
@Override 註解,編譯器自動校驗規則
最佳實踐
- 所有覆蓋方法**強制加
@Override**
- 設計可擴展類時,核心算法骨架用
final 方法,變化點開放 protected abstract 或可覆蓋方法(模板方法模式)
- 重載方法參數類型盡量差異明顯,避免自動裝箱/類型提升導致調用歧義
- 文檔化覆蓋契約:前置條件、後置條件、不變量
- 上一篇文章: Java 單例模式雙重檢查鎖與餓漢式代碼實戰
- 下一篇文章: Java Comparator 接口實作與排序實戰範例
Copyright ©
程式碼之家 All Rights Reserved