Java SE 5 引入自動裝箱與拆箱,讓基本型別與包裝類別可自動轉換。編譯器在編譯期插入 valueOf()(裝箱)與 xxxValue()(拆箱)呼叫,位元碼層面仍建立包裝物件。範例:
Integer i = 7; // 編譯為 Integer i = Integer.valueOf(7); int n = i; // 編譯為 int n = i.intValue();
為提升效能、減少物件建立開銷,Java 規範要求對常用數值進行快取:
Integer、Short、Long、Byte:快取 -128 至 127 範圍內的物件Character:快取 0 至 127(Unicode BMP 範圍)Boolean:快取 TRUE、FALSE 兩個單例Float、Double:不快取,因浮點數值無限且無明顯熱點值Integer.valueOf() 實作邏輯:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
Integer a = 100, b = 100; // true(快取範圍內,同一物件參考) Integer c = 200, d = 200; // false(超出快取,新建物件) Integer e = new Integer(100); // false(new 強制建立新物件) Integer f = 100; // true(valueOf 回傳快取物件)
核心結論:== 比較的是參考位址,唯有快取範圍內透過 valueOf() 取得的物件才會回傳 true。實務上永遠使用 equals() 比較包裝類別數值。
Integer i = 7;),享受快取優勢,減少物件分配null 自動拆箱會拋 NullPointerException,需防禦性檢查使用 javap -c 反編譯可見編譯器插入的 invokestatic java/lang/Integer.valueOf 與 invokevirtual java/lang/Integer.intValue 指令,證明機制在編譯期實現,JVM 執行期無感知。