以下测试用例将通过:
@Test
public void assignWrapperTest() {
System.out.printf("\nassign - %s\n", "wrapper");
Integer a = 1000;
Integer b = a;
System.out.printf("a = %d, b = %d\n", a, b);
Assert.assertEquals(a, b);
Assert.assertSame(a, b); // a, b are the same object,
a++;
System.out.printf("a = %d, b = %d\n", a, b);
Assert.assertNotEquals(a, b);
Assert.assertNotSame(a, b); // a, b are not the same object, any more,
}
所以:
a
被++
更改。b
保持不变。问题是:
b = a
只是给参考值赋权,它们指向的是同一个对象,此时只有一个对象,对吧?++
创建了一个新的Integer对象,并将其自动分配回原始变量?如果是这种情况,这是否意味着a
现在指向另一个对象?b
仍指向原始位置吗?答案 0 :(得分:10)
a++;
由于a
是Integer
,因此与以下内容相同:
a = Integer.valueOf(a.intValue() + 1);
这是否意味着
++
创建了一个新的Integer对象
也许(但不一定):Integer.valueOf
将重用缓存的值;仅当超出缓存范围(至少-128..127)时,才会创建一个新值。
答案 1 :(得分:4)
如果我们看Byte code
的{{1}},如下图所示:
a++
所以指令就像获得 9: aload_1
10: invokevirtual #22 // Method java/lang/Integer.intValue:()I
13: iconst_1
14: iadd
15: invokestatic #16 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
18: astore_1
中的intValue()
,然后a
,然后对增量值调用increment
,然后Integer#valueOf创建一个新对象。
答案 2 :(得分:1)
a++
有效地执行了a=a+1
(忽略了将其转换为Integer
的逻辑)。表达式a+1
的结果为一个新的int
,该表达式被分配给a
。b
的值尚未被先前的操作所触及,因此它仍指向同一对象。答案 3 :(得分:1)
是的
Integer
对象是不可变的。但是,他们持有的引用是可变的。
Integer
类,缓存数据并重用它们。
让我们看看您的代码中发生了什么。
Integer a = 1000;
//假设它在堆中创建了一个4字节的内存块,地址引用为&addr_of_val_1000;
Integer b = a;
//现在,b指向地址引用&addr_of_val_1000;
a++;
//这会在堆中/从堆中创建/获取新值1001
,并使用新的地址引用&addr_of_val_1001;
并将其分配给变量a
所以
a = 1001和b = 1000不相等。 &addr_of_val_1000!=&addr_of_val_1001(它们的引用不再相同)
但是,如果您添加
b++;
或
b = Integer.valueOf(1001)
在您进行检查之前,它们将是相同的并且再次相同。
答案 4 :(得分:0)
关键是Integer
是immutable
。
如果操作数是可变的,例如int
,++
运算符,只需将1
添加到原始值 。
对于Integer
,这是不同的。通过a++
,创建了Integer
的新实例,其值来自于将1
和{{1}都添加到原始Integer对象中}指向,然后将a
重新分配给该新对象。 b
仍引用原始的Integer对象,因此a
和b
现在不相同。