Java 5 引入自動裝箱與自動拆箱,消除了原始類型與對應包裝類之間手動轉換的樣板代碼。這不是 JVM 新指令,而是編譯器在編譯期自動插入轉換代碼的語法糖。理解其運作機制,能避免效能陷阱、空指針風險與語義誤解。
| 術語 | 方向 | 舊寫法 | 新寫法 | 編譯器插入 |
|---|---|---|---|---|
| Autoboxing (自動裝箱) | primitive → Wrapper | |||
| Unboxing (自動拆箱) | Wrapper → primitive |
public class BoxingDemo {
public static void main(String[] args) {
Integer wrapper = new Integer(8);
int primitive = 9;
foo(primitive); // 自動裝箱
bar(wrapper); // 自動拆箱
}
static void foo(Integer val) { System.out.println("foo: " + val); }
static void bar(int val) { System.out.println("bar: " + val); }
}
public static void main(java.lang.String[]);
Code:
0: new #2 // class java/lang/Integer
3: dup
4: bipush 8
6: invokespecial #3 // Method "":(I)V
9: astore_1
10: bipush 9
12: istore_2
13: iload_2
14: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; ← 自動裝箱
17: invokestatic #5 // Method foo:(Ljava/lang/Integer;)V
20: aload_1
21: invokevirtual #6 // Method java/lang/Integer.intValue:()I ← 自動拆箱
24: invokestatic #7 // Method bar:(I)V
27: return
#14 invokestatic Integer.valueOf:編譯器將 foo(primitive) 轉為 foo(Integer.valueOf(primitive))#21 invokevirtual Integer.intValue:編譯器將 bar(wrapper) 轉為 bar(wrapper.intValue())Integer.valueOf(int) 對 -128 ~ 127 範圍內的整數回傳快取實例Integer a = 100; Integer b = 100; a == b → true(同一快取物件)Integer c = 200; Integer d = 200; c == d → false(新建物件).equals(),不可用 ==
Integer wrapper = null;
int primitive = wrapper; // 執行時拋出 NPE(編譯通過,運行炸裂)
wrapper.intValue(),若 wrapper 為 null 即拋出 NPE
void m(int i) { }
void m(Integer i) { }
m(10); // 呼叫 m(int) —— 原始類型優先
m(new Integer(10)); // 呼叫 m(Integer)
long 和 Integer 重載,int 會擴展為 long 而非裝箱為 Integer(擴展優於裝箱)
boolean flag = true;
Integer a = 1;
int b = 2;
Number result = flag ? a : b; // 結果類型為 int(拆箱後擴展為 Number)
// 實際編譯為:flag ? a.intValue() : b → int → 裝箱為 Integer → Number
.equals()int),內部實作視情況用包裝類表達「可缺失」javac -source 1.5 -target 1.5 確保啟用特性自動裝箱/拆箱是 Java 5 最貼近開發日常的語法糖,極大提升了集合與泛型操作的流暢度。但其本質是編譯期插入 valueOf()/xxxValue() 呼叫,帶來快取語義、NPE 風險、效能開銷與重載解析細節。專業開發者應享受便利、理解代價、規避陷阱,在正確場合做正確選擇。