動態綁定是 Java 實現多態的核心機制。當子類覆寫父類方法,並透過子類實例調用父類繼承的方法時,究竟會執行哪個版本的方法?本文透過經典代碼範例徹底釐清動態綁定的判斷邏輯與運行時行為。
class Base {
int i = 47;
int f() { return g(); }
int g() { return i; }
}
class Derived extends Base {
int i = 27; // 隱藏父類欄位
int g() { return i; } // 覆寫父類方法
}
public class Test {
public static void main(String[] args) {
Derived d = new Derived();
System.out.println(d.f()); // 輸出什麼?
}
}
d.f() 呼叫 Base.f()(子類未覆寫 f())Base.f() 內部執行 return g();g() 是靜態綁定還是動態綁定?「調用當前對象實際類型的方法」 —— 運行時根據對象的真實類型(而非引用類型)決定調用哪個方法版本。
d 的實際類型是 Derivedg() 解析為 Derived.g()Derived.g() 返回 this.i,即 Derived 的 i = 27| 概念 | 說明 | 本例表現 |
|---|---|---|
| 靜態綁定 | 編譯期根據引用類型決定(private、static、final、建構子) | 不適用於本例 g() |
| 動態綁定 | 運行期根據對象實際類型決定(普通實例方法) | g() 綁定至 Derived.g() |
| 欄位隱藏 | 子類同名欄位隱藏父類欄位,非覆寫,靜態綁定 | Base.i=47, Derived.i=27 互不干擾 |
| 方法覆寫 | 子類同簽名方法覆寫父類,動態綁定 | Derived.g() 覆寫 Base.g() |
動態綁定讓「同一介面、不同實作」成為可能:父類定義演算法骨架(f()),子類提供具體步驟實作(g()),運行時自動選擇正確版本。這正是範本方法模式的語言級支撐,也是 Java 物件導向多態的基石。
Base.f() 內呼叫 g() 會綁定 Base.g() —— 錯誤,綁定看對象實際類型。i 也會動態綁定 —— 錯誤,欄位存取靜態綁定,Base.f() 中若直接存取 i 會得到 47。