我正在比较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
?参考文献不应该有所不同吗?
答案 0 :(得分:18)
这与拳击工作有关。来自JLS section 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
答案 1 :(得分:6)
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**
答案 2 :(得分:3)
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
,因此引用无法通过等于==
运算符测试
但是,这里还有一些值得思考的东西。
Integer i=300;
Integer j=300;
if(i!=j)System.out.println("i!=j"); // prints i!=j
为什么呢?因为,自动装箱仅在-128到127之间共享Integer
个实例。但是,这种行为在不同的Java实现之间可能会有所不同。
答案 3 :(得分:2)
我怀疑在第一个片段中为什么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 pattern。
答案 4 :(得分:1)
不,他们不应该,因为java可以在自动装箱时使用预制的Integer对象来获取小数字。
答案 5 :(得分:0)
因为在第二个代码中你的第一个整数是自动装箱的,而第二个不是。
这意味着即时创建一个新的Integer实例。这两个对象实例是不同的。由于两个实例实际上是不同的内存块,因此相等性检查将返回false。
答案 6 :(得分:0)
Interpreter / JIT优化器可以将所有3个放在同一个框中。但是如果你强迫一个“新”,那么你会得到另一个地址。
尝试
j=8; // after initialization of i and j
然后看到j的地址已更改为第一个版本。
答案 7 :(得分:0)
以类似方式使用字符串时,使用自动装箱时,例如
Integer i = 3;
Integer j = 3;
Java可以从预制对象池中提取。在j
的情况下,已经有一个Integer
实例表示池中3
的值,因此它从中抽取。因此,i
和j
指向相同的事物,因此i == j
。
在第二个示例中,您明确地为Integer
实例化了一个新的j
对象,因此i
和j
指向不同的对象,因此{{1} }。
答案 8 :(得分:0)
在下面的代码中:
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”,第二个代码没有任何输出。
希望这有帮助。