| 成員類型 | 訪問規則 | 綁定時機 | 關鍵字 |
|---|---|---|---|
| 實例字段 | 按引用聲明類型選擇入口 | 編譯期靜態綁定 | 無動態分派 |
| 實例方法 | 按對象實際類型查找方法表 | 運行期動態綁定 | 虛方法分派 |
| 靜態方法 | 按引用聲明類型解析 | 編譯期靜態綁定 | 無多態性 |
class A { String name = "A"; int a = 1; }
class B extends A { String name = "B"; int b = 2; }
A a = new A();
A b1 = new B(); // 向上轉型
B b2 = new B();
System.out.println(a.name); // A
System.out.println(a.a); // 1
System.out.println(b1.name); // A —— 引用類型 A,入口在 A
System.out.println(b1.a); // 1
// System.out.println(b1.b); // 編譯錯誤:A 無字段 b
System.out.println(((B)b1).name); // B —— 強轉後引用類型 B
System.out.println(((B)b1).b); // 2
System.out.println(b2.name); // B
System.out.println(b2.b); // 2
B 對象內存佈局:
┌──────────────────┐
│ A 部分: name="A" │ ← 父類字段
│ a=1 │
├──────────────────┤
│ B 部分: name="B" │ ← 子類字段(遮蔽父類同名字段)
│ b=2 │
└──────────────────┘
A 類型引用 → 入口指向 A 部分
B 類型引用 → 入口指向 B 部分
字段無多態,編譯器根據引用靜態類型直接計算偏移量訪問。
class Father { void show() { System.out.println("Father"); } }
class Child extends Father { @Override void show() { System.out.println("Child"); } }
Child c = new Child();
Father f = c; // 向上轉型
c.show(); // Child
f.show(); // Child —— 動態綁定到 Child 實現
Klass 元數據(方法表)。invokevirtual 指令 → 在對象實際類型的方法表中查找方法簽名 → 執行對應字節碼。class Father { static void show() { System.out.println("Father static"); } }
class Child extends Father { static void show() { System.out.println("Child static"); } }
Child c = new Child();
Father f = c;
c.show(); // Child static
f.show(); // Father static —— 編譯期按 Father 類型解析
靜態方法屬於類,不屬於實例,invokestatic 指令編譯期直接綁定具體類的方法,無動態分派,不構成重寫,僅是隱藏。
public class PolyAccessDemo {
public static void main(String[] args) {
// 字段
Parent p = new Child();
System.out.println("字段 p.val = " + p.val); // Parent.val
System.out.println("字段 (Child)p.val = " + ((Child)p).val); // Child.val
// 實例方法
p.instanceMethod(); // Child 版本
// 靜態方法
p.staticMethod(); // Parent 版本
Child.staticMethod(); // Child 版本
}
}
class Parent {
int val = 100;
void instanceMethod() { System.out.println("Parent instance"); }
static void staticMethod() { System.out.println("Parent static"); }
}
class Child extends Parent {
int val = 200;
@Override void instanceMethod() { System.out.println("Child instance"); }
static void staticMethod() { System.out.println("Child static"); }
}
多態訪問決策樹
┌─────────────────┐
│ 成員類型 │
└────────┬────────┘
│
┌──────────┼──────────┐
▼ ▼ ▼
實例字段 實例方法 靜態方法
│ │ │
▼ ▼ ▼
引用類型 對象實際類型 引用類型
(靜態綁定) (動態綁定) (靜態綁定)
│ │ │
▼ ▼ ▼
父類入口 子類方法表 父類解析
訪問父字段 執行子實現 執行父靜態
子類字段 (多態核心) (隱藏非重寫)
需強轉訪問
徹底掌握三類成員在多態下的訪問語義,能避免 90% 的「以為多態實則靜態綁定」類 Bug,也是面試高頻考點與框架源碼閱讀的基礎能力。