9

我正在比较两段代码。第一的

Integer i=3;
Integer j=3;
if(i==j)
   System.out.println("i==j");  //prints i==j              

第二,

Integer i=3;
Integer j=new Integer(3);
if(i==j)
   System.out.println("i==j"); // does not print

我怀疑在第一个片段中为什么i==j要打印?参考文献不应该不同吗?

4

9 回答 9

18

这与拳击的工作方式有关。从JLS 部分 5.1.7

如果被装箱的值 p 是真、假、一个字节或 \u0000 到 \u007f 范围内的一个字符,或者一个介于 -128 和 127(含)之间的 int 或短数字,则令 r1 和 r2 为p 的任意两个拳击转换。r1 == r2 总是如此。

基本上,Java 实现必须缓存适当小的值的装箱表示,并且可以缓存更多。运算符只是比较引用,因此==它专门检测两个变量是否引用同一个对象。在第二个代码片段中,他们肯定不会,因为new Integer(3)绝对不是与以前创建的任何引用相同的引用......它总是创建一个新对象。

由于上述规则,此代码必须始终给出相同的结果:

Integer x = 127;
Integer y = 127;
System.out.println(x == y); // Guarantee to print true

而这可能会以任何一种方式进行:

Integer x = 128;
Integer y = 128;
System.out.println(x == y); // Might print true, might print false
于 2013-07-05T17:35:35.807 回答
6

Java 池化介于 -128 和 127 之间的整数,因此两个引用是相同的。

Integer i=3;
Integer j=3;

这导致自动装箱,并且 3 被转换为整数 3。因此,对于 i 指的是常量池中的整数对象,现在当您执行 j=3 时,将与 i 的引用相同的引用分配给 j。

而下面的代码:

Integer j=new Integer(3);

总是会在堆中创建一个新的整数。这不是汇集的。因此,您会看到两个引用都指向不同的对象。这导致

Integer i=3;
Integer j=new Integer(3);
if(i==j)
   System.out.println("i==j"); // **does not print**
于 2013-07-05T17:34:52.593 回答
3

我怀疑在第一个片段中为什么要打印 i==j ?参考文献不应该不同吗?

因为,

    Integer i=3;
    Integer j=3;

在内部使用Integer#valueOf()来执行autoBoxing. oracle doc 谈到了valueOf()以下方法:

返回一个表示指定 int 值的 Integer 实例。如果不需要新的 Integer 实例,则通常应优先使用此方法而不是构造函数 Integer(int),因为此方法可能会通过缓存频繁请求的值来显着提高空间和时间性能。此方法将始终缓存 -128 到 127(含)范围内的值,并且可能缓存此范围之外的其他值。

由于该值3被缓存,因此两个变量ij引用同一个对象。所以,i==j正在回归trueInteger#valueOf()使用享元模式

于 2013-07-05T17:38:49.520 回答
3
Integer i=3;
Integer j=3;
if(i==j)System.out.println("i==j");

在这里,3被自动装箱,因此ij指向同一个Integer

Integer i=3;
Integer j=new Integer(3);
if(i==j)System.out.println("i==j"); // does not print

在这里,i指向自动装箱Integer,而j指向新的Integer,因此引用失败等于==运算符测试。

但是,这里还有一些值得深思的地方。

Integer i=300;
Integer j=300;
if(i!=j)System.out.println("i!=j"); // prints i!=j

为什么?因为,自动装箱Integer仅在 -128 到 127 之间共享实例。然而,这种行为可能在不同的 Java 实现之间有所不同。

于 2013-07-05T17:40:57.077 回答
1

不,他们不应该,因为在自动装箱时,java 可以将预制的 Integer 对象用于少量数字。

于 2013-07-05T17:34:19.820 回答
0

因为在第二段代码中,您的第一个整数是自动装箱的,而第二个不是。

这意味着正在动态创建一个新的 Integer 实例。这两个对象实例是不同的。相等性检查将在那里返回 false,因为这两个实例实际上是不同的内存。

于 2013-07-05T17:33:53.557 回答
0

解释器/JIT 优化器可以将所有 3 放在同一个框中。但是,如果您强制使用“新”,那么您将获得另一个地址。

尝试

 j=8; // after initialization of i and j

然后看到 j 的地址更改为第一个版本。

于 2013-07-05T17:35:32.993 回答
0

在以下代码中:

Integer i=3;
Integer j=3;
if(i==j)
   System.out.println("i==j");

这里,“==”比较的是引用而不是值。因此,整数 i 和 j 都指的是内存中的相同引用。

在以下代码中:

Integer i=3;
Integer j=new Integer(3);
if(i==j)
   System.out.println("i==j");

对这两个值的引用都发生了变化,因为“j”是内存中新创建的整数对象/引用,而“i”只是指一个值。

因此,第一个代码的输出是“i==j”,第二个代码没有任何输出。

希望这可以帮助。

于 2013-07-12T10:15:17.803 回答
0

类似于字符串的方式,当使用自动装箱时,例如在

Integer i = 3;
Integer j = 3;

Java 可以从预制对象池中提取。在 的情况下j,池中已经有一个Integer表示 的值的实例3,因此它从中提取。因此ij指向同一事物,因此i == j

在您的第二个示例中,您Integerj, soij指向不同的对象显式实例化一个新对象,因此i != j

于 2013-07-05T17:37:58.953 回答