自動裝箱/拆箱是語法糖,但 == 與 equals() 在包裝類上的行為差異是高頻面試題與生產 Bug 源頭。通過反編譯還原本質。
Integer a = 1; // → Integer a = Integer.valueOf(1); (裝箱)
Integer c = a + b; // → a.intValue() + b.intValue() → Integer.valueOf(結果) (拆箱運算裝箱)
結論:賦值字面量調用 valueOf(),運算觸發 intValue() 拆箱後再 valueOf() 裝箱。
Integer c = 3, d = 3; // valueOf(3) 返回緩存對象 → c == d → true
Integer e = 321, f = 321; // valueOf(321) new Integer(321) → e == f → false
源碼驗證 IntegerCache 靜態初始化緩存區間,可通過 -Djava.lang.Integer.IntegerCache.high=... 調整上限。
Integer a = 1, b = 2, c = 3, d = 3, e = 321, f = 321;
Long g = 3L;
System.out.println(c == d); // true (緩存同一對象)
System.out.println(e == f); // false (新建對象)
System.out.println(c == (a + b)); // true (a+b 拆箱運算 → 3 → 裝箱 valueOf(3) 緩存 → c 同一對象)
System.out.println(c.equals(a+b)); // true (equals 比較 intValue)
System.out.println(g == (a + b)); // true (g 拆箱 long,a+b 拆箱 int → int 提升 long 比較)
System.out.println(g.equals(a+b)); // false (Long.equals 要求參數 instanceof Long,Integer 不符合)
| 表達式 | 結果 | 本質原因 |
|---|---|---|
| 包裝類 == 包裝類 (緩存區間) | true | valueOf 返回同一緩存引用 |
| 包裝類 == 包裝類 (非緩存區間) | false | new 出不同對象 |
| 包裝類 == 算術表達式 | true/false | 算術觸發拆箱運算 → 裝箱 → 緩存判斷 |
| 包裝類.equals(算術表達式) | true | 算術結果裝箱後 equals 比較值 |
| 不同包裝類 == (Long vs Integer) | true | 基本類型提升比較 (long) |
| 不同包裝類.equals(不同包裝類) | false | equals 先判 instanceof 本類型 |
// Integer.equals
public boolean equals(Object obj) {
return obj instanceof Integer && value == ((Integer)obj).intValue();
}
// Long.equals
public boolean equals(Object obj) {
return obj instanceof Long && value == ((Long)obj).longValue();
}
鐵律:equals 嚴格要求同類型,跨類型直接返回 false,不進行數值轉換。
==int/long,邊界交互再裝箱💡 阿里巴巴開發手冊:【強制】所有的包裝類對象之間值的比較,全部使用
equals()方法比較。