Java 中 Long 比较的 “127 陷阱”:为什么超过 127 后不能用 ==?

在 Java 开发中,Long 作为 long 的包装类,经常需要进行比较操作。然而开发者常会遇到一个奇怪现象:当 Long 对象值 ≤127 时,== 比较返回 true;当值 >127 时,== 却返回 false,必须使用 equals 方法才能正确比较。这究竟是怎么回事?让我们深入解析这个 “127 陷阱”。

一、现象观察:127 是分界线

通过以下代码可以直观看到这个现象:

public class LongCompareDemo {
    public static void main(String[] args) {
        Long a = 127L;
        Long b = 127L;
        System.out.println(a == b); // true
        
        Long c = 128L;
        Long d = 128L;
        System.out.println(c == d); // false
        System.out.println(c.equals(d)); // true
    }
}

同样的比较操作,127 时 == 返回 true,128 时却返回 false。这不是 Java 的 bug,而是 Long 的缓存机制与 == 运算符特性共同作用的结果。

二、原理分析:自动装箱与缓存机制

1. == 运算符的行为特性

在 Java 中:

  • 比较基本类型(如 long、int)时,== 比较值是否相等
  • 比较引用类型(如 Long、String)时,== 比较对象内存地址是否相同

Long 是引用类型,因此 Long a == Long b 实际上是判断两个变量是否指向同一个对象。

2. 自动装箱与缓存实现

Long a = 127L 这样的赋值会触发自动装箱,底层调用的是 Long.valueOf(long)。查看源码(JDK 8):

public static Long valueOf(long l) {
    final int offset = 128;
    if (l >= -128 && l <= 127) { // 缓存范围
        return LongCache.cache[(int)l + offset];
    }
    return new Long(l); // 超出范围创建新对象
}

缓存机制的关键点:

  • 值在 -128~127 范围内时,返回缓存中的 Long 对象
  • 超出该范围时,每次都会新建 Long 对象

这就是为什么 127 时 == 比较返回 true(指向同一缓存对象),而 128 时 == 比较返回 false(新建不同对象)。

三、正确做法:使用 equals 方法

Long 类重写了 equals 方法,会正确比较包装的 long 值:

public boolean equals(Object obj) {
    if (obj instanceof Long) {
        return value == ((Long)obj).value;
    }
    return false;
}

因此,比较 Long 对象的值时,应该始终使用 equals 方法。

四、开发注意事项

  1. 明确区分类型:

    • long:基本类型,用 == 比较
    • Long:包装类,用 equals 比较
  2. 警惕自动装箱:

    • 方法参数为 Long 时,传入 long 值会触发自动装箱
    • 例如 method(128L) 会产生新对象
  3. 其他包装类:

    • Integer/Short/Byte:缓存范围 -128~127
    • Character:缓存范围 0~127
    • Double/Float:无缓存机制

五、总结要点

"127 陷阱"的根源:

  1. == 比较的是对象引用而非值
  2. Long 对 -128~127 范围内的值做了缓存

最佳实践:

  • 比较包装类对象时,始终使用 equals 方法
  • 理解 == 和 equals 的本质区别:前者比较对象身份,后者比较对象值
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐