在 Java 開發中,我們常聽到「包裝類是不可變類」這句話。對於初學者來說,這往往令人困惑:明明我可以寫 Integer i = 10; i = 20;,值不是變了嗎?這篇文章將從記憶體分配、引用機制與類設計三個維度,徹底釐清這個核心概念。
首先必須區分「對象本身」與「指向對象的引用」。
當我們執行 Integer it = 21; 時,發生了兩件事:
Integer 對象。it,指向該對象。當代碼執行到 it = 22; 時:
Integer 對象。it 斷開與舊對象(21)的連接,轉而指向新對象(22)。關鍵點: 值為 21 的對象從未被修改過,修改的是引用 it 指向的目標。這就像「人(引用)換了房子(對象)住,但房子本身沒變」。
// 初始化
Integer it = 21;
// 棧: it --------------------> 堆: [Integer Object: value=21]
// 重新賦值
it = 22;
// 棧: it --------------------> 堆: [Integer Object: value=22]
// 堆: [Integer Object: value=21] (無引用,待 GC)
Integer 類內部沒有任何 setValue() 之類的方法來修改內部的 value 字段(該字段被 final 修飾)。這帶來了重要優勢:
Integer.valueOf() 機制)。HashMap 鍵或 HashSet 元素,避免值變更導致找不到對象。誤區:
int a = 21;也是引用指向堆?事實:基本類型
int直接在棧中存儲數值 21,無堆對象、無引用概念。自動裝箱才會創建Integer對象。
「包裝類不可變」意味著:一個包裝類對象一旦創建,其封裝的數值永遠不能改變。 變量賦值新值實際上是創建新對象並讓引用指向它。理解「棧存引用,堆存對象」的記憶體模型,是掌握 Java 核心機制的關鍵一步。