为什么 = = 与 Integer.valueOf (String)的比较会给出127和128的不同结果?

我不知道为什么这些代码行返回不同的值:

System.out.println(Integer.valueOf("127")==Integer.valueOf("127"));
System.out.println(Integer.valueOf("128")==Integer.valueOf("128"));
System.out.println(Integer.parseInt("128")==Integer.valueOf("128"));

输出结果是:

true
false
true

为什么第一个返回 true,第二个返回 false127128之间有什么我不知道的不同吗?(我当然知道 127 < 128。)

另外,为什么第三个返回 true

我已经阅读了 这个问题的答案,但是我仍然不明白它如何返回 true,以及为什么第二行的代码返回 false

19010 次浏览

这里有一个显著的区别。

valueOf正在返回一个 Integer对象,该对象的值可能缓存在 -128和127之间。这就是为什么第一个值返回 true-它是缓存的-而第二个值返回的 false-128不是缓存的值,因此您将得到两个单独的 Integer实例。

需要注意的是,您正在比较引用和 Integer#valueOf,如果您比较的值大于缓存支持的值,那么即使解析的值是等价的(例如: Integer.valueOf(128) == Integer.valueOf(128)) ,没有的计算结果也将等于 true。您使用 必须的而不是 equals()

parseInt正在返回一个基元 int。这就是为什么第三个值返回 true-128 == 128被计算,当然也就是 true

现在,第三个结果正好是 true:

整数对象缓存在 -128和256个整数中的127之间

不应该将对象引用与 ==!=进行比较。你应该用。取而代之的是 等于(. .),或者更好的方法是使用原语 int 而不是 Integer。

ParseInt : 将字符串参数解析为有符号的十进制整数。字符串中的字符必须都是十进制数字,但是第一个字符可以是 ASCII 减号’-’(’u002D’) ,以表示负值。返回结果的整数值,就好像参数和基数10是作为 parseInt (java.lang)的参数给出的一样。String,int)方法。

价值 返回一个 Integer 对象,该对象包含在使用第二个参数给定的基数进行分析时从指定的 String 中提取的值。第一个参数被解释为在第二个参数指定的基数中表示一个有符号整数,就好像这些参数被赋予 parseInt (java.lang)一样。String,int)方法。结果是一个 Integer 对象,表示字符串指定的整数值。

等同于

new Integer(Integer.parseInt(s, radix))

基数-用于解释 s 的基数

所以如果中间的整数等于 Integer.valueOf()

-128到127在你的情况下它返回真

对于 lesser than-128和 greater than-127,它给出 false

Integer类有一个静态缓存,它存储256个特殊的 Integer对象——每个值对应一个 -128和127之间的值。记住这一点,考虑一下这三者之间的区别。

new Integer(123);

这(显然)使一个全新的 Integer对象。

Integer.parseInt("123");

这将在解析 String之后返回一个 int基元值。

Integer.valueOf("123");

这比其他的更复杂。它首先解析 String。然后,如果该值介于 -128和127之间,它将从静态缓存返回相应的对象。如果该值超出了这个范围,那么它将调用 new Integer()并传入该值,以便您获得一个新对象。

现在,考虑问题中的三个表达式。

Integer.valueOf("127")==Integer.valueOf("127");

这将返回 true,因为值为127的 Integer将从静态缓存中检索两次,并与其本身进行比较。只涉及一个 Integer对象,因此它返回 true

Integer.valueOf("128")==Integer.valueOf("128");

这将返回 false,因为128不在静态缓存中。因此等式的每一边都创建了一个新的 Integer。因为有两个不同的 Integer对象,而对象的 ==只有在两边是完全相同的对象时才返回 true,所以这将是 false

Integer.parseInt("128")==Integer.valueOf("128");

这将比较左边的原始 int值128和右边新创建的 Integer对象。但是因为将 intInteger进行比较是没有意义的,Java 将在进行比较之前自动解压 Integer; 所以您最终将 intint进行比较。因为原语128等于它自己,所以返回 true

注意从这些方法返回值。 价值方法返回一个 Integer 实例:

public static Integer valueOf(int i)

ParseInt方法返回整数值(基元类型) :

public static int parseInt(String s) throws NumberFormatException

比较解释:

方法的两个实例 包装器对象时,总是 = = 基本值是相同的:

  • 布尔型
  • 再见
  • 字符由 u0000至 u007f (7f 为小数点后127位)
  • Short 和 Integer 从 -128到127

当使用 = = 将基元与包装器进行比较时,包装器将为 取消包装,并且比较将是原始到原始的。

在你的情况下(根据上述规则) :

Integer.valueOf("127")==Integer.valueOf("127")

此表达式比较对同一对象的引用,因为它包含 -128和127之间的 Integer 值,所以它返回 true

Integer.valueOf("128")==Integer.valueOf("128")

这个表达式比较对不同对象的引用,因为它们包含的 Integer 值不在 <-128,127 > 中,所以它返回 false

Integer.parseInt("128")==Integer.valueOf("128")

这个表达式比较基元值(左边)和对象的引用(右边) 所以右边将被打开,他的基元类型将与左边进行比较,所以它返回 true

为了补充给出的答案,还要注意以下几点:

public class Test {
public static void main(String... args) {
Integer a = new Integer(129);
Integer b = new Integer(129);
System.out.println(a == b);
}
}

此代码也将打印: false

正如用户 在注释中声明的那样,在对象上使用操作符 ==时必须小心,这里你要检查两个引用是否相同,其实不是,因为它们是不同的对象,尽管它们表示相同的值。要比较对象,应该使用 equals方法:

Integer a = new Integer(128);
Integer b = new Integer(128);
System.out.println(a.equals(b));

这将打印: true

您可能会问,但是为什么第一行打印的是 true。检查 Integer.valueOf方法的源代码,您可以看到以下内容:

public static Integer valueOf(String s) throws NumberFormatException {
return Integer.valueOf(parseInt(s, 10));
}


public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

如果参数是 IntegerCache.low(默认为 -128)和 IntegerCache.high(在运行时以最小值127计算)之间的整数,则返回预分配(缓存)对象。因此,当您使用127作为参数时,您将获得对同一缓存对象的两个引用,并在引用的比较中获得 true