| 術語 | 代碼形式 | 動作 | 內存影響 |
|---|---|---|---|
| 聲明引用變量 | Y b; | 在棧幀分配引用變量槽位(4/8 字節),初始值為 null | 無堆對象創建 |
| 創建對象 | new Y() | 在堆分配對象內存,調用構造函數初始化,返回引用地址 | 堆分配對象,返回地址 |
| 賦值/初始化 | b = new Y() | 將創建對象返回的地址存入引用變量 b | 引用變量指向堆對象 |
| 合寫 | Y b = new Y(); | 聲明 + 創建 + 賦值,一條語句完成 | 等價於分開寫 |
棧 堆
┌──────────────┐ ┌────────────────────┐
│ main() 幀 │ │ Y 實例 │
│ Y b ─────────┼──────────────────►│ 字段... │
│ (引用變量) │ 地址 0x7f... │ 方法表指針 │
└──────────────┘ └────────────────────┘
class X {
T b = new Y(); // 成員變量聲明處初始化
X() {
System.out.print("X");
}
}
編譯器會將成員初始化代碼**自動搬移到構造函數開頭**,等價於:
class X {
T b;
X() {
b = new Y(); // 編譯器插入這裡,super() 之後、構造函數體之前
System.out.print("X");
}
}
Y b; // ① 聲明引用,b = null
b = new Y(); // ② 創建對象,賦值給 b
Y c = b; // ③ 複製引用,c 指向同一對象
c = new Y(); // ④ 創建新對象,c 指向新對象,b 不變
問題:執行 ④ 後,堆上有幾個 Y 對象?
答案:**兩個**。`b` 和 `c` 分別指向不同對象,第一個對象若無其他引用,將被 GC 回收。
| 特性 | 實例變量 | 靜態變量 |
|---|---|---|
| 歸屬 | 屬於對象實例 | 屬於類 |
| 創建時機 | 每次 `new` 時 | 類加載時(首次主動使用) |
| 內存區域 | 堆 | 方法區/元空間 |
| 訪問方式 | `obj.field` | `Class.field` 或 `obj.field`(不推薦) |
| 生命週期 | 隨對象 GC 結束 | 隨類卸載結束(通常伴隨 JVM) |