我不知道为什么这些代码行返回不同的值:
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
而第二个返回 false
? 127
和 128
之间有什么我不知道的不同之处吗? (我当然知道 127
< 128
。)
另外,为什么第三个返回 true
?
我已阅读答案 of this question,但我仍然不明白它如何返回 true
,以及为什么第二行中的代码返回 false
。
.equals()
,否则所有赌注都将关闭。
这里有一个显着的区别。
valueOf
正在返回一个 Integer
对象,它的值可能缓存在 -128 和 127 之间。这就是为什么第一个值返回 true
- 它已缓存 - 而第二个值返回 false
- 128 不是一个缓存值,因此您将获得两个单独的 Integer
实例。
请务必注意,您正在将引用与 Integer#valueOf
进行比较,如果您正在比较的值大于缓存支持的值,则它不会评估为true
,即使解析的值是等价的(例如:Integer.valueOf(128) == Integer.valueOf(128)
)。您必须改用 equals()
。
parseInt
正在返回一个原始 int
。这就是为什么第三个值返回 true
- 128 == 128
被评估,当然是 true
。
现在,恰好使第三个结果 true
:
对于您正在使用的等价运算符和您拥有的数据类型(即 int 和 Integer),会发生拆箱转换。当然,您从右侧的 valueOf 获得一个 Integer 。
转换后,您将比较两个原始 int 值。比较的发生与您对基元的预期一样,因此您最终比较了 128 和 128。
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
对象进行比较。但是因为比较 int
和 Integer
没有意义,Java 会在比较之前自动拆箱 Integer
;因此您最终会将 int
与 int
进行比较。由于原语 128 等于其自身,因此返回 true
。
注意从这些方法返回值。 valueOf 方法返回一个 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 之间的整数值,因此它返回 true
。
Integer.valueOf("128")==Integer.valueOf("128")
此表达式比较对不同对象的引用,因为它们包含不在 <-128, 127> 中的整数值。所以它返回 false
。
Integer.parseInt("128")==Integer.valueOf("128")
此表达式比较原始值(左侧)和对对象的引用(右侧),因此右侧将被展开,其原始类型将与左侧进行比较,因此返回 true
。
整数对象缓存在 -128 和 127 之间,共 256 个整数
您不应将对象引用与 == 或 != 进行比较。您应该使用 .equals(..) 代替,或者更好 - 使用原始 int 而不是 Integer。
parseInt:将字符串参数解析为有符号十进制整数。字符串中的字符必须都是十进制数字,除了第一个字符可以是 ASCII 减号“-”(“\u002D”)表示负值。返回结果整数值,就好像参数和基数 10 作为参数提供给 parseInt(java.lang.String, int) 方法一样。
valueOf 返回一个 Integer 对象,当使用第二个参数给出的基数进行解析时,该对象包含从指定 String 中提取的值。第一个参数被解释为表示由第二个参数指定的基数中的有符号整数,就像将参数提供给 parseInt(java.lang.String, int) 方法一样。结果是一个表示字符串指定的整数值的 Integer 对象。
相当于
new Integer(Integer.parseInt(s, radix))
radix - 用于解释 s 的基数
因此,如果您之间的整数等于 Integer.valueOf()
-128 到 127 它在您的情况下返回 true
对于 lesser than
-128 和 greater than
127 它给出 false
为了补充给定的答案,还请注意以下几点:
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
正如用户 Jay 在评论中声明的已接受答案,在对象上使用运算符 ==
时必须小心,在这里您要检查两个引用是否相同,这不是,因为它们是不同的对象,尽管它们代表相同的值。要比较对象,您应该改用 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
。
List
。另一个是原始值,它只是一个原始值。==
。无论如何,它现在清楚了。