Java自动装箱/拆箱在比较中易出错,主因是==比较引用或值取决于操作数类型,且Integer等在[-128,127]有缓存:范围内==可能为true,范围外为false;推荐用Objects.equals()或转基本类型比较。

Java 的自动装箱(autoboxing)和拆箱(unboxing)在比较运算中容易引发“看似相等却为 false”或“本该不等却为 true”的意外结果,核心原因在于:== 比较的是引用还是值,取决于操作数是否为基本类型;而 Integer 等包装类在 -128 到 127 范围内有缓存机制。
Integer 缓存导致 == 比较结果不稳定
当你用 == 比较两个 Integer 对象时,如果它们的值在 [-128, 127] 范围内,JVM 会复用缓存对象,此时 == 可能返回 true;超出该范围则新建对象,== 返回 false —— 即使数值相同。
- Integer a = 100; Integer b = 100; → a == b 是 true(都指向常量池中同一个缓存对象)
- Integer c = 200; Integer d = 200; → c == d 是 false(各自 new 出不同对象)
- Integer e = 200; int f = 200; → e == f 是 true(e 自动拆箱为 int,再按数值比较)
Boolean、Character 等也有类似缓存行为
Boolean 只有 true/false 两个实例,所以 Boolean.TRUE == Boolean.TRUE 总是 true;Character 在 [0, 127] 范围内也缓存,但超出后 == 就不可靠。而 Long、Short、Byte 缓存范围也是 [-128, 127],Float 和 Double 则不缓存,所以 new Float(1.0f) == new Float(1.0f) 永远是 false(== 比较的是两个不同对象的引用)。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
用 equals() 也不完全安全
看似用 a.equals(b) 就能避免问题?不一定:
立即学习“Java免费学习笔记(深入)”;
- 如果 a 为 null,调用 equals 会抛 NullPointerException
- 如果传入非同类型参数(如 new Integer(5).equals("5")),结果是 false(不报错但逻辑易错)
- Float/Double 的 equals 会把 NaN 视为相等(Float.NaN.equals(Float.NaN) 是 true),而 == 比较 NaN 却是 false —— 行为不一致
安全比较的实践建议
- 比较数值时,优先使用 == 仅当至少有一个操作数是基本类型(触发自动拆箱),例如 integerObj == intPrimitive
- 两个包装类比较,统一转成基本类型再比:integer1.intValue() == integer2.intValue()(注意空指针)
- 使用 Objects.equals(a, b),它内部处理了 null 安全和类型判断,推荐用于通用场景
- 对浮点数,避免 == 或 equals,改用 Double.compare(d1, d2) == 0 或设定误差范围判断

















