Java中用==比较包装类对象时,结果取决于缓存机制:Byte、Short、Integer、Long、Character、Boolean有缓存,Float和Double无缓存;缓存范围内复用对象使==为true,范围外或new创建则为false;应优先使用Objects.equals()安全比较值。

Java 中使用 == 比较两个包装类对象时,结果可能出人意料——有时相等,有时不等。这并非 bug,而是包装类的缓存机制(如 IntegerCache)与 == 的语义共同作用的结果:它比较的是引用是否指向同一对象,而非值是否相等。
哪些包装类有缓存?缓存范围是多少?
只有 Byte、Short、Integer、Long、Character 和 Boolean 在特定条件下启用缓存;Float 和 Double 没有缓存机制。
-
Boolean:缓存true和false两个实例 -
Byte、Short、Integer、Long:默认缓存 [-128, 127] 范围内的值(可由 JVM 参数调整,如-XX:AutoBoxCacheMax=200影响Integer) -
Character:缓存 [0, 127] 的字符(即 ASCII 可见字符及控制符)
为什么 == 有时为 true,有时为 false?
关键在于装箱(autoboxing)是否复用缓存中的对象:
- 在缓存范围内,通过直接赋值或
valueOf()创建的对象通常指向同一个缓存实例 →==返回true - 超出缓存范围,每次装箱都会新建对象 → 引用不同 →
==返回false - 显式调用
new Integer(100)总是创建新对象,即使值在缓存范围内,也绕过缓存 →==必为false
例如:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
立即学习“Java免费学习笔记(深入)”;
Integer a = 100; // 缓存内 → 指向 IntegerCache[100] Integer b = 100; // 同上 → 与 a 是同一对象 System.out.println(a == b); // true Integer c = 200; // 缓存外 → 新建对象 Integer d = 200; // 另一个新对象 System.out.println(c == d); // false Integer e = new Integer(100); // 强制 new → 不走缓存 System.out.println(a == e); // false
如何安全地比较包装类的值?
始终用 .equals() 比较逻辑值,但需注意 null 安全:
- 推荐写法:
Objects.equals(a, b)(自动处理null) - 若确定非 null,可用
a.equals(b);但a为null会抛NullPointerException - 数值比较也可用对应方法,如
Integer.compare(a, b) == 0
避免依赖 == 判断值相等,尤其在涉及用户输入、数据库读取或配置参数等不可控来源时。
实际开发中容易踩的坑
- 在 if 条件中写
if (status == StatusEnum.SUCCESS)—— 若StatusEnum是自定义枚举,没问题;但若误写成Integer status = ...,且值来自 JSON 解析(可能超出缓存),==就可能失效 - 单元测试用字面量(如
Integer i = 5)通过,但生产环境数据来自外部系统(如150),测试未覆盖边界 → 上线后逻辑异常 - 用
==判断Boolean时看似稳定(因只有两个缓存实例),但一旦变量为null,==不报错却逻辑错误(null == true是false,但本意可能是“是否为 true”)

















