1. 概述
在本篇短文中,我们将深入探讨 Java 中比较两个 Long
对象的不同方式,并重点分析使用 ==
进行引用比较时可能踩的坑。
对于有经验的开发者来说,这看似基础,但在实际项目中,因误用 ==
导致的 Bug 并不少见。本文将帮你彻底理清思路,避免掉进“看似正常、实则危险”的陷阱。
2. 使用引用比较(==)的问题
Long
是 long
基本类型的包装类。既然是对象,**比较内容时就必须使用 .equals()
,而不是 ==
**。因为 ==
比较的是对象引用,而非实际数值。
但为什么有时候 ==
看起来也能工作?
Long l1 = 127L;
Long l2 = 127L;
assertThat(l1 == l2).isTrue();
这段代码返回 true
,容易让人误以为 ==
是安全的。但换一个数字:
Long l1 = 128L;
Long l2 = 128L;
assertThat(l1 == l2).isFalse();
结果变成了 false
!⚠️ 这就是典型的“踩坑”场景。
原因解析
Java 对 Long
类型做了缓存优化:在 -128 到 127 范围内的 Long
值会被缓存,多次赋值会复用同一个对象实例。而超出这个范围的值则每次都会创建新对象。
✅ 所以:
127L
被缓存,l1
和l2
指向同一个对象 →==
为true
128L
不在缓存范围 → 生成两个不同对象 →==
为false
但这绝不意味着你可以依赖这种行为。缓存是 JVM 的实现细节,不能作为编码依据。
3. 使用 .equals() 方法
最直接、最标准的解决方案是使用 .equals()
方法,它比较的是对象的实际数值内容。
Long l1 = 128L;
Long l2 = 128L;
assertThat(l1.equals(l2)).isTrue();
✅ 优点:
- 正确性有保障
- 语义清晰
❌ 缺点:
- 如果
l1
为null
,调用l1.equals(l2)
会抛出NullPointerException
所以,当存在 null
可能时,直接调用 .equals()
是危险的。
4. 使用 Objects.equals()(推荐)
为了解决 null
安全问题,Java 提供了 Objects.equals()
工具方法,它是 null
安全的。
Long l1 = null;
Long l2 = 128L;
assertThat(Objects.equals(l1, l2)).isFalse();
assertThat(Objects.equals(null, null)).isTrue();
原理
Objects.equals(a, b)
内部逻辑如下:
return (a == b) || (a != null && a.equals(b));
✅ 优点:
- 自动处理
null
,无需额外判空 - 语义清晰,代码简洁
- 是官方推荐的最佳实践
⚠️ 建议:在比较可能为 null
的包装类型时,优先使用 Objects.equals()
5. 解包 Long 值进行比较
如果你确定值不为 null
,也可以通过解包(unboxing)转为基本类型 long
后再用 ==
比较。
5.1 使用 .longValue() 方法
Long l1 = 128L;
Long l2 = 128L;
assertThat(l1.longValue() == l2.longValue()).isTrue();
5.2 强制类型转换
Long l1 = 128L;
Long l2 = 128L;
assertThat((long) l1 == (long) l2).isTrue();
这两种方式本质相同,都是将 Long
对象解包为 long
基本类型。
⚠️ 重要提醒:
- 如果对象为
null
,调用.longValue()
或(long) null
都会抛出NullPointerException
- 因此,使用前必须确保非
null
,否则不如直接用Objects.equals()
6. 总结与建议
方法 | 是否推荐 | 适用场景 |
---|---|---|
== |
❌ | 禁止用于 Long 值比较 |
.equals() |
⚠️ | 确保对象非 null 时可用 |
Objects.equals() |
✅✅✅ | 首选方案,安全且简洁 |
解包比较(.longValue() 或强转) |
⚠️ | 确认非 null 且追求极致性能时可考虑 |
最佳实践
- **一律使用
Objects.equals(l1, l2)
**,简单粗暴,一劳永逸 - 避免手动解包,除非在性能敏感场景且能保证非
null
- 永远不要依赖
-128~127
的缓存行为
所有示例代码已上传至 GitHub:https://github.com/baeldung/core-java(模块:core-java-lang-2)