整数i = 3 vs Integer i = new Integer(3)

我正在比较2段代码。 第一

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正在打印? 参考文献不应该有所不同吗?

这与拳击工作有关。 从JLS部分5.1.7 :

如果被装箱的值p为真,假,字节或范围为\ u0000到\ u007f的字符,或介于-128和127(含)之间的整数或短数,则让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 

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

 Integer i=3; Integer j=3; 

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

以下代码:

 Integer j=new Integer(3); 

总是在堆中导致新的Integer创建。 这不是合并的。 因此,您会看到两个引用都指的是不同的对象。 结果如何

 Integer i=3; Integer j=new Integer(3); if(i==j) System.out.println("i==j"); // **does not print** 
 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指向自动加框的Integerj指向一个新的Integer ,因此引用失败了equals ==运算符测试。

但是,这里还有一些值得思考的东西。

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

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

我怀疑在第一个片段中为什么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()使用flyweight模式 。

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

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

这意味着即时创建了一个新的Integer实例。 这两个对象实例是不同的。 由于两个实例实际上是不同的内存块,因此相等性检查将返回false。

Interpreter / JIT优化器可以将所有3个放在同一个框中。 但如果你强迫一个“新”,那么你得到另一个地址。

尝试

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

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

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

 Integer i = 3; Integer j = 3; 

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

在你的第二个例子中,你明确地为j实例化一个新的Integer对象,所以ij指向不同的对象,因此i != j

在下面的代码中:

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

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

而在下面的代码中:

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

对两个值的引用都会更改,因为’j’是内存中新生成的Integer对象/引用,而’i’只是指一个值。

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

希望这可以帮助。