Java 的八大基本類型(byte、short、int、long、float、double、char、boolean)不是對象,無法直接泛型、集合存儲、調用方法。為賦予其對象特性,Java 為每種基本類型提供了對應的包裝類(Byte、Short、Integer、Long、Float、Double、Character、Boolean),均繼承自 Number 或 Object,且為 final 不可繼承、內部值不可變。
核心場景:
ArrayList<Integer> list = new ArrayList<>(); list.add(3);— 基本類型int自動轉為Integer對象,這就是自動裝箱;取出時int n = list.get(0);自動轉回int,即自動拆箱。
裝箱/拆箱發生在編譯期,由 javac 插入字節碼指令,JVM 僅執行生成的字節碼。反編譯可見:
// 源碼
list.add(3);
int n = list.get(0);
// 編譯器生成等效字節碼
list.add(Integer.valueOf(3)); // 裝箱:調用靜態工廠方法
int n = list.get(0).intValue(); // 拆箱:調用實例方法
// 手動裝箱(JDK 9+ 已棄用構造器,推薦 valueOf)
Integer manual = new Integer(10); // 每次 new 創建新對象,性能差
// 自動裝箱
Integer auto = 10; // 實為 Integer.valueOf(10)
Integer obj = Integer.valueOf(20);
// 手動拆箱
int manual = obj.intValue();
// 自動拆箱
int auto = obj; // 實為 obj.intValue()
Integer.valueOf(int i) 內部維護 [-128, 127] 的緩存池(可通過 -XX:AutoBoxCacheMax 調整上限),範圍內直接返回緩存對象,避免重複創建:
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; // 緩存範圍內
Integer c = 200, d = 200; // 緩存範圍外
System.out.println(a == b); // true(同一緩存對象)
System.out.println(c == d); // false(不同 new 對象)
// 結論:包裝類比較值務必用 equals(),禁止用 ==
看似簡單的累加,實則製造大量臨時對象:
Integer sum = 0;
for (int i = 1000; i < 5000; i++) {
sum += i; // 反編譯見真章
}
// 等效字節碼邏輯:
// 1. sum.intValue() // 拆箱
// 2. + i // 基本類型加法
// 3. Integer.valueOf() // 裝箱賦值給 sum
// 每次循環創建一個新 Integer 對象,4000 次循環 = 4000 個對象,GC 壓力劇增!
// 方案一:使用基本類型局部變量累加,最後裝箱
int sum = 0;
for (int i = 1000; i < 5000; i++) sum += i;
Integer result = sum;
// 方案二:LongAdder / AtomicLong(高併發場景)
LongAdder adder = new LongAdder();
for (int i = 1000; i < 5000; i++) adder.add(i);
包裝類不僅是容器,還封裝了豐富靜態工具方法,如:
Integer.parseInt("123")、Double.parseDouble("3.14") — 字符串轉基本類型Integer.toBinaryString(10) — 進制轉換Integer.compare(5, 3) — 避免溢出的安全比較(JDK 7+)Integer.MAX_VALUE、MIN_VALUE — 常量定義equals(),緩存範圍外 == 會翻車。Integer obj = null; if (obj > 0) 會拋 NPE(拆箱時調用 null.intValue())。valueOf() 或自動裝箱,利用緩存優勢。自動裝箱/拆箱是 Java 語法糖,極大提升了編碼便利性,但並非零成本。理解其編譯期本質、緩存機制、循環中隱性對象創建的性能代價,並在熱點路徑採用基本類型替代,是進階 Java 開發者必備的性能調優直覺。下次看到 List<Integer> 循環累加時,請記住:一個 int 變量,勝過千萬個 Integer 對象。