社交媒体

自动装箱:== 引发的事故

自动装箱:== 引发的事故

钩子:一行代码,测出你的 Java 底子

Integer a = 127;
Integer b = 127;
System.out.println(a == b);    // true

Integer c = 128;
Integer d = 128;
System.out.println(c == d);    // false!!!

同样的写法,127 是 true,128 是 false。第一次见到的人都会怀疑电脑坏了。

核心:装箱和拆箱到底是什么

上篇说过 ArrayList<int> 写不了,得写 ArrayList<Integer>——集合只认对象,不认基本类型。为了不让来往搬运太麻烦,Java 提供了自动转换:

Integer x = 100;      // 自动装箱:int → Integer(编译器偷偷写 Integer.valueOf(100))
int y = x + 1;        // 自动拆箱:Integer → int(编译器偷偷加 x.intValue())

"自动"的意思是编译器替你写了代码——代码没少跑,只是你没看见。

正题:127 和 128 的区别在哪

秘密在 Integer.valueOf 里:Java 预先造好了 -128 到 127 这 256 个 Integer 对象,放进缓存池。

  • 装箱值在 -128~127 之间:直接从池里拿,两次拿的是同一个对象 → == 比地址,true;
  • 超出范围:现场 new 一个新对象,两次装箱是两个对象 → == 比地址,false。

26-Integer缓存池区间图.png

事故现场:这个坑怎么咬人

库存系统里数量用 Integer 存(能表示 null,比 int 方便),某天对账:

Integer stock1 = 128;   // 从数据库查的
Integer stock2 = 128;   // 从缓存查的
if (stock1 == stock2) { ... }   // 缓存生效前是 false,数量永远"对不上"

测试环境数量小(< 128)一切正常,一上生产数量过千就出灵异事件。修复只要一个词:equals。

第 22 篇的口诀原样适用:== 比地址,equals 比内容。Integer 是对象,对象比较用 equals,没有例外。

第二颗雷:null 拆不箱

前面那道题的雷,现在引爆:

Map<String, Integer> price = new HashMap<>();
int p = price.get("banana");    // get 返回 null → 拆箱 → NullPointerException

get 没查到返回 null,没问题;但赋给 int 要拆箱——null 是"没有对象",拆不成 int,直接 NPE。

两颗雷一个解法:包装类型比较用 equals;跟基本类型混算之前,先判 null(或用 getOrDefault(key, 0) 给默认值)。

速查表

写法 结果 原因
Integer a=127, b=127; a==b true 命中缓存池,同一对象
Integer a=128, b=128; a==b false 超出缓存,两个对象
Integer 与 int 用 == 比值(拆箱) 但 Integer 为 null 时 NPE
包装类型比较 永远 equals 比内容,稳
map.get(key) 赋给 int 可能 NPE null 拆不箱,先判空

本文示例代码均已本地实测通过,可直接运行。
对应文件:BoxingDemo.java


橙码酱,分享更有用的技术知识,助你成为更优秀的开发者。