| 維度 | 基本類型 | 包裝類型 |
|---|---|---|
| 類別 | byte/short/int/long/float/double/boolean/char | Byte/Short/Integer/Long/Float/Double/Boolean/Character |
| 默認值 | 0/0.0/false/'\u0000' | null |
| 存儲位置 | 棧幀局部變量表 / 對象實例字段 | 堆內存(對象),引用在棧 |
| 傳遞方式 | 值傳遞(複製數值) | 引用傳遞(複製地址) |
| 方法支持 | 無 | 豐富(parseInt, toString, compareTo...) |
| 泛型支持 | 不支持 | 支持(List<Integer>) |
| 性能 | 極高(直接操作數值) | 較低(對象創建、GC、拆裝箱開銷) |
// 基本類型:棧上直接存值
int a = 10; // 棧幀槽位直接存 10
int b = a; // 複製值 10 到 b 槽位
b = 20; // a 仍為 10,互不影響
// 包裝類型:堆上存對象,棧存引用
Integer x = new Integer(10); // 堆創建對象,x 存引用地址
Integer y = x; // 複製引用,指向同一對象
y = 20; // 自動拆箱→裝箱,y 指向新對象,x 不變
// 裝箱:基本類型 -> 包裝類型
Integer i1 = 100; // 編譯器轉為 Integer.valueOf(100)
Integer i2 = Integer.valueOf(100); // 手動調用
// 拆箱:包裝類型 -> 基本類型
int n = i1; // 編譯器轉為 i1.intValue()
int m = i1.intValue(); // 手動調用
// 表達式中自動拆裝箱
Integer a = 10;
Integer b = 20;
Integer c = a + b; // a.intValue() + b.intValue() -> 結果裝箱 Integer.valueOf(30)
Integer a = 100;
Integer b = 100;
System.out.println(a == b); // true(緩存命中)
Integer c = 200;
Integer d = 200;
System.out.println(c == d); // false(超出緩存範圍,新對象)
// 緩存範圍:-128 ~ 127(可通過 -XX:AutoBoxCacheMax=1000 擴大)
// 源碼邏輯:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
鐵律:包裝類型比較值必須用 equals(),== 只比較引用地址。
// 糟糕:每次循環拆箱相加、裝箱存回
Integer sum = 0;
for (int i = 0; i < 1000000; i++) {
sum += i; // sum.intValue() + i -> Integer.valueOf() -> 新對象
}
// 優化:用基本類型累加,最後裝箱
int sum = 0;
for (int i = 0; i < 1000000; i++) {
sum += i;
}
Integer result = sum;
List list = new ArrayList<>();
list.add(1); // 自動裝箱 Integer.valueOf(1)
// 取出時自動拆箱
int n = list.get(0); // list.get(0).intValue()
大數據量場景考慮:
int[]Eclipse Collections、FastUtil、Koloboke 提供基本類型集合| 場景 | 推薦 | 理由 |
|---|---|---|
| 純計算、高頻調用 | 基本類型 | 無對象創建、棧上分配、JIT 優化最好 |
| 需要 null 表達「無值」 | 包裝類型 | 基本類型無 null 語義 |
| 泛型集合、反射、框架 API | 包裝類型 | 泛型擦除要求對象類型 |
| DTO/VO/實體類字段 | 包裝類型 | 區分「未設置」與「設置為 0」 |
// 字符串 -> 基本類型(靜態解析方法)
int i = Integer.parseInt("123");
long l = Long.parseLong("456");
double d = Double.parseDouble("3.14");
boolean b = Boolean.parseBoolean("true");
// 基本類型 -> 字符串
String s1 = String.valueOf(123); // 推薦,null 安全
String s2 = Integer.toString(123); // 同值
String s3 = 123 + ""; // 隱式轉換,產生 StringBuilder
// 包裝類型 -> 字符串
Integer obj = 123;
String s4 = obj.toString(); // 實例方法
String s5 = String.valueOf(obj); // 靜態方法,null 返回 "null"
equals()IntegerCache 範圍,勿依賴 == 行為基本類型與包裝類型的二元設計是 Java「一切皆對象」妥協產物。深理解其內存語義、拆裝箱機制、緩存行為與性能特徵,是寫出高性能、正確 Java 代碼的基石。現代 JDK 持續優化(逃逸分析、標量替換、值類型項目 Valhalla),但基本原理不變,工程選型需權衡表達力與性能。