| 區域 | 儲存內容 | 生命週期 |
|---|---|---|
| 方法區 | 類別定義、常量、靜態變數、方法字節碼 | JVM 啟動 ~ 關閉 |
| 堆 | 物件實例、陣列、實例變數(屬性) | GC 管理 |
| 棧 | 局部變數、方法呼叫框架 | 執行緒私有,隨方法進出 |
static 修飾 → **方法區**(屬於類別,共享唯一副本)。static → **堆**(屬於物件,每 new 一次分配一份)。問題提到「屬性存儲在哪裡」,若指類別定義層面的屬性描述(名稱、型別、修飾符),則在方法區;若指運行時具體數值,實例屬性在堆,靜態屬性在方法區。
class Parent { String name = "Parent"; }
class Child extends Parent { String name = "Child"; }
Parent p = new Child();
System.out.println(p.name); // 輸出 "Parent" —— 編譯期靜態綁定
System.out.println(((Child)p).name); // 輸出 "Child"
核心規則:
override 方法由 JVM 依實際物件型別動態分派。Child 物件在堆中佈局:
+------------------+
| Parent.name | <-- 父類屬性槽位
+------------------+
| Child.name | <-- 子類屬性槽位 (遮蔽父類)
+------------------+
| 其他實例欄位... |
+------------------+
protected 屬性,子類直接使用,勿重複宣告。getter/setter 封裝存取,若子類需不同行為,覆寫方法而非屬性。Java 屬性分為靜態(方法區)與實例(堆);父子類同名屬性屬於遮蔽,依參考型別靜態綁定,不具備多型特性。理解此機制能避免「以為覆蓋了父類屬性」的常見 Bug。