整数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
是自动装箱的,因此i
和j
指向同一个Integer
。
Integer i=3; Integer j=new Integer(3); if(i==j)System.out.println("i==j"); // does not print
在这里, i
指向自动加框的Integer
而j
指向一个新的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
被缓存,因此变量i
和j
都引用相同的对象。 所以, i==j
返回true
。 Integer#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
,因此它从中抽取。 因此, i
和j
指向相同的东西,因此i == j
。
在你的第二个例子中,你明确地为j
实例化一个新的Integer
对象,所以i
和j
指向不同的对象,因此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”,第二个代码没有任何输出。
希望这可以帮助。