Java 中變數的生命週期包含三個階段:**宣告 → 分配記憶體 → 初始化**。許多開發者誤以為宣告即分配記憶體,實際上:
nullclass Person {
String name;
int age;
void talk() { System.out.println("我是: " + name + ", 今年: " + age + "歲"); }
}
public class Test {
public static void main(String[] args) {
Person p; // 僅宣告,未初始化
if (p == null) { // 編譯錯誤:variable p might not have been initialized
p = new Person();
}
p.name = "張三";
p.age = 25;
p.talk();
}
}
Test.java:59: error: variable p might not have been initialized
if (p == null) {
編譯器禁止使用**未明確初始化**的區域參考變數,即使邏輯上 p 預設為 null。這是 Java「確定性賦值分析」的體現,防止使用未初始化變數導致的 NullPointerException。
Person p = null; // 明確初始化:分配參考槽位 + 賦值 null
if (p == null) { // 合法
p = new Person(); // 分配物件記憶體,p 指向新物件
}
| 特性 | 基本型別 (int, boolean...) | 參考型別 (Person, String...) |
|---|---|---|
| 宣告時動作 | 棧上分配記憶體,設預設零值 | 棧上分配參考槽位(4/8B),值為 null |
| 預設值 | 0, 0.0, false, '\u0000' | null |
| 物件記憶體分配 | 不適用(無物件) | new 時於堆上分配 |
| 賦值語意 | 複製數值 | 複製參考(指向同一物件) |
| 範例 | int a; // a=0 |
Person p; // p=null |
new 或賦值非 null 時在堆分配物件null| 誤區 | 正確理解 |
|---|---|
| 宣告參考型別就建立物件 | 宣告只建立「遙控器」,new 才建立「電視機」 |
Person p = null 沒分配記憶體 |
分配了參考槽位(棧上 4/8 bytes),只是指向「無物件」 |
| 基本型別和參考型別記憶體模型相同 | 基本型別存「值」,參考型別存「地址」,根本不同 |
int a; 未初始化 |
區域變數編譯器視為未初始化(需明確賦值),成員變數已自動為 0 |
null:明確語意,滿足編譯器檢查,便於靜態分析工具new 至真正需要時NPE 風險Java 變數記憶體模型的核心在於**基本型別存值、參考型別存址**。宣告階段對基本型別分配數值空間,對參考型別僅分配參考槽位。編譯器的確定性賦值分析強制區域變數使用前明確初始化,這是 Java 型別安全的重要保障。深入理解此機制,能避免大量 NullPointerException 與邏輯錯誤,寫出更健壯的程式碼。