比较包装的Long值127和128

116

我想使用if条件比较两个Long对象的值。当这些值小于128时,if条件可以正常工作,但当它们大于或等于128时,比较失败。

示例:

Long num1 = 127;
Long num2 = 127;

if (num1 == num2) {
    // Works ok
}

上面的代码比较正常,但下面的代码失败了:

Long num1 = 128;
Long num2 = 128;

if (num1 == num2) {
    // Does NOT work
}

为什么使用值大于127的Long变量进行比较会出现问题?如果将变量的数据类型更改为long基元,则可以在所有情况下进行比较。

4个回答

219

简短版

Java缓存了从-128到127的包装整数对象。使用“==”比较对象引用而不是值,只有缓存的对象才能匹配。要么使用未包装的长整型原始值,要么使用“.equals()”比较Long对象。

详细版

为什么在比较大于127的Long变量时会出现问题?如果上述变量的数据类型是原始类型(long),则代码对所有值都有效。

Java缓存了范围在-128到127之间的Integer对象实例,因此:

  • 如果将N个Long变量设置为值为127已缓存),则所有引用将指向同一对象实例。(N个变量,1个实例)
  • 如果将N个Long变量设置为值128未缓存),则每个引用都将指向一个对象实例。(N个变量,N个实例)

这就是为什么会出现以下情况:

Long val1 = 127L;
Long val2 = 127L;

System.out.println(val1 == val2);

Long val3 = 128L;
Long val4 = 128L;

System.out.println(val3 == val4);

输出结果为:

true
false

对于值127L,由于两个引用(val1和val2)指向内存中相同的对象实例(已缓存),它返回true

另一方面,对于值128,由于它在内存中没有缓存的实例,因此为装箱值分配任何新值将创建一个新的对象实例,导致两个不同的实例(由val3和val4指向),并在它们之间的比较中返回false

这仅仅是因为你正在使用==运算符来比较两个Long 对象引用,而不是long原始类型的值。如果没有这个缓存机制,这些比较将总是失败,所以真正的问题是使用==运算符比较装箱值。

将这些变量更改为原始的long类型将防止这种情况发生,但如果您需要保持使用Long对象的代码,则可以通过以下方法安全地进行比较:

System.out.println(val3.equals(val4));                     // true
System.out.println(val3.longValue() == val4.longValue());  // true
System.out.println((long)val3 == (long)val4);              // true

即使进行强制类型转换,适当的空值检查也是必要的。

在我看来,处理对象比较时,使用.equals()方法总是一个好主意。

参考链接:


15

Java缓存从-128到127的原始值。当我们比较两个Long对象时,Java会内部将其类型转换为基本类型值并进行比较。但是超过127的Long对象将不会被强制转换。Java使用.valueOf()方法缓存输出。

对于Byte、Short和Long,缓存适用于-128到127。 对于Integer,缓存适用于从-128到java.lang.Integer.IntegerCache.high或127中较大的值。(我们可以使用java.lang.Integer.IntegerCache.high设置顶级值,以便缓存Integer值的上限)。

 For example:
    If we set java.lang.Integer.IntegerCache.high=500;
    then values from -128 to 500 will get cached and 

    Integer a=498;
    Integer b=499;
    System.out.println(a==b)

    Output will be "true".

浮点数和双精度对象永远不会被缓存。

字符将在0到127之间进行缓存

您正在比较两个对象。因此, == 运算符将检查对象引用的相等性。以下是几种方法。

1)将两个对象强制转换为原始值并进行比较

    (long)val3 == (long)val4

2) 读取对象的值并进行比较

    val3.longValue() == val4.longValue()

3) 使用equals()方法进行对象比较。

    val3.equals(val4);  

15

num1num2是Long对象。您应该使用equals()方法进行比较。==比较有时可能会起作用,因为JVM将基本类型装箱,但不要依赖它。

if (num1.equals(num1))
{
 //code
}

1
这个(哪个更好),或者比较.longValue()的返回值。 - Giulio Franco

4
在Java中,使用==比较非原始类型(也称为对象)时,比较的是它们的引用而不是它们的值。 Long是一个类,因此Long的值是对象。

问题在于Java开发人员希望人们像使用long一样使用Long以提供兼容性,这导致了自动装箱的概念,即将long值按需更改为Long对象,反之亦然。尽管自动装箱的行为并非完全可预测,但请安全起见并始终使用.equals()来比较对象,不要在此情况下依赖自动装箱:

Long num1 = 127, num2 = 127;
if(num1.equals(num2)) { iWillBeExecutedAlways(); }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接