1. 概述

在本篇短文中,我们将深入探讨 Java 中比较两个 Long 对象的不同方式,并重点分析使用 == 进行引用比较时可能踩的坑。

对于有经验的开发者来说,这看似基础,但在实际项目中,因误用 == 导致的 Bug 并不少见。本文将帮你彻底理清思路,避免掉进“看似正常、实则危险”的陷阱。

2. 使用引用比较(==)的问题

Longlong 基本类型的包装类。既然是对象,**比较内容时就必须使用 .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 被缓存,l1l2 指向同一个对象 → ==true
  • 128L 不在缓存范围 → 生成两个不同对象 → ==false

但这绝不意味着你可以依赖这种行为。缓存是 JVM 的实现细节,不能作为编码依据。

3. 使用 .equals() 方法

最直接、最标准的解决方案是使用 .equals() 方法,它比较的是对象的实际数值内容。

Long l1 = 128L;
Long l2 = 128L;

assertThat(l1.equals(l2)).isTrue();

✅ 优点:

  • 正确性有保障
  • 语义清晰

❌ 缺点:

  • 如果 l1null,调用 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)


原始标题:Comparing Long Values in Java