int 是基本型別,Integer 是其包裝類別。這對看似簡單的關係,實則包含記憶體模型、效能考量、語言設計哲學等深層議題。本文從基礎差異切入,深入剖析自動裝箱拆箱機制、Integer 快取範圍、== 比較陷阱與最佳實踐。
| 維度 | int | Integer |
|---|---|---|
| 型別分類 | 基本型別 | 參考型別(類別) |
| 記憶體儲存 | Stack(棧)直接存值 | Heap(堆)存物件,棧存參考 |
| 預設值 | 0 | null |
| 記憶體佔用 | 4 bytes | ~16 bytes (物件頭 + 值 + 參考) |
| 可為 null | 否 | 是 |
| 泛型支援 | 不可(List<int> 錯誤) | 可(List<Integer> 正確) |
| 方法呼叫 | 不可 | 可(parseInt、toString、compareTo 等) |
Java 5 引入編譯器語法糖,自動在基本型別與包裝類別間轉換:
// 裝箱:int -> Integer
Integer a = 100; // 編譯為 Integer.valueOf(100)
Integer b = Integer.valueOf(100);
// 拆箱:Integer -> int
int c = a; // 編譯為 a.intValue()
int d = a + b; // 隱式拆箱進行運算
// 陷阱:null 拆箱拋 NPE
Integer n = null;
int crash = n; // NullPointerException
為了效能,Integer.valueOf(int) 對 -128 到 127 範圍內的整數維護快取池:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
// 快取範圍可透過 JVM 參數調整
// -XX:AutoBoxCacheMax=2000
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true(快取命中)
Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false(新物件,比較參考位址)
// 正確比較方式
System.out.println(c.equals(d)); // true
System.out.println(Objects.equals(c, d)); // 安全防 null
Integer x = new Integer(100); // 強制建立新物件,不走快取
Integer y = Integer.valueOf(100); // 走快取
System.out.println(x == y); // false
System.out.println(x.equals(y)); // true
// Java 9+ 已棄用 new Integer(),建議統一用 valueOf() 或 parseInt()
List list = new ArrayList<>();
list.add(100); // 自動裝箱 -> Integer.valueOf(100)
list.add(200); // 新物件
// 移除元素陷阱
list.remove(100); // 呼叫 remove(int index) 移除索引 100,而非值 100!
list.remove(Integer.valueOf(100)); // 正確:呼叫 remove(Object) 移除值
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class IntegerBenchmark {
@Benchmark
public int primitiveLoop() {
int sum = 0;
for (int i = 0; i < 1000; i++) sum += i;
return sum;
}
@Benchmark
public int boxedLoop() {
Integer sum = 0;
for (int i = 0; i < 1000; i++) sum += i; // 大量裝箱拆箱
return sum;
}
}
// 典型結果:primitive ~500ns, boxed ~5000ns (慢 10 倍)
| 包裝類別 | 快取範圍 |
|---|---|
| Byte | -128 ~ 127 (全域) |
| Short | -128 ~ 127 |
| Integer | -128 ~ 127 (可調整上限) |
| Long | -128 ~ 127 |
| Character | 0 ~ 127 (ASCII) |
| Boolean | TRUE/FALSE 兩個單例 |
| Float/Double | 無快取 |
理解 int 與 Integer 的差異不只是語法層面,更關乎記憶體模型、效能特徵與語言設計權衡。掌握快取機制、正確比較方式、避免無謂裝箱,是寫出高品質 Java 代碼的基本功。