多態是面向對象編程的基石,Java 通過**繼承**與**接口**實現子類型多態。本文將從**多態分類學**、**面向類型觀點**、**引用與對象綁定機制**、**接口多態的獨特價值**、**JVM 層面動態分派實現**五個維度,構建完整的多態知識體系。
學術界將多態劃為兩大類四小類:
| 大類 | 小類 | 定義 | Java 體現 |
|---|---|---|---|
| 特定多態 | 強制多態 | 隱式類型轉換 | double + int → double、Derived → Base 向上轉型 |
| 重載多態 | 同名標識符多義 | 方法重載、+ 運算符重載 (字符串拼接) | |
| 通用多態 | 參數多態 | 類型參數化 | 泛型 List<T> (Java 5+),但類型擦除限制了完全體現 |
| 包含多態 | 子類型包含關系 | Java 核心多態:繼承 + 接口實現 |
本文聚焦 **包含多態 (子類型多態)**。
採用 UML 類圖建立類型層次:
Interface IType
▲
│
Class Base ← Derived ← Derived2
│
Class Separate (實現 IType)

Derived2 derived2 = new Derived2();

Base base = derived2;

base 僅可見 Base 定義的方法 (m1(), m2()),不可見 Derived2 特有方法 (m3(), m4())。base.m1() 執行 Derived2 覆寫版本 — **動態分派核心證據**。Derived2 d2 = new Derived2(); Base b = d2; IType i = d2;
三個引用指向同一對象,方法調用遵循:**編譯看引用類型,運行看對象類型**。
void poly1(Base b) { b.m1(); }
poly1(new Base()); // 執行 Base.m1()
poly1(new Derived()); // 執行 Derived.m1()
poly1(new Derived2()); // 執行 Derived.m1() (Derived2 未覆寫 m1)
poly1(new Separate()); // 編譯錯誤:Separate 非 Base 子類

多態魅力: poly1 編譯後**無需修改**,即可支援所有當前及未來的 Base 子類 — **開閉原則 (OCP) 完美體現**。
void poly2(IType i) { i.m3(); }
poly2(new Derived2()); // 執行 Derived2.m3()
poly2(new Separate()); // 執行 Separate.m3() — 無共享代碼,純類型契約

接口多態核心價值:
Derived2 繼承 Base 代碼,實現 IType 契約;Separate 無任何代碼共享,僅實現契約。IType 抽象,低層模塊實現 IType,雙方依賴抽象。invokestatic:靜態方法,編譯期綁定。invokespecial:私有方法、構造器、super 調用,編譯期綁定。invokevirtual:**實例方法,運行期動態分派** — 多態核心指令。invokeinterface:接口方法調用,同樣動態分派。invokedynamic:Lambda/動態語言支援 (JDK 7+)。invokevirtual 邏輯:obj.vtable[methodIndex] → 直接跳轉,**O(1) 極快**。if (klass == Derived) ...),仍比查表快。invokevirtual。類型決定「調什麼」,實現決定「怎麼調」。
多態將「責任」 (類型契約) 與「履行」 (具體代碼) 分離。
繼承提供代碼複用維度,接口提供類型契約維度。
JVM 以 vtable + JIT 內聯實現高性能動態分派,動態語言特性 (invokedynamic) 進一步拓展邊界。
理解多態不僅是語法熟練,更是掌握**面向對象設計精髓**與**JVM 運行時機制**的雙重鑰匙。