初学Java问题:我什么时候
Integer i = 6;
ArrayList<Integer> ar = ArrayList<Integer>();
ar.add(i);
然后我写i = 8
,ar.get(0)
返回6
。
但如果我和我的一类人一样:
class MyC
{
Integer i;
}
MyC myc = new MyC();
myc.i = 6;
ArrayList<MyC> ar = ArrayList<MyC>();
ar.add(myc);
然后执行myc.i = 8
,ar.get(0)
返回8
。
你能解释一下这种行为吗?
答案 0 :(得分:2)
问题与自动装箱无关,正如一些答案所说的那样。
在第一个示例中,您创建一个Integer并将其放在ArrayList
中。
然后将指针更改为Integer,以便i
指向另一个Integer。
这不会影响ArrayList
的整数。
在第二个示例中,您将创建一个对象并将其放在ArrayList
中。
然后,您通过myc.i = 8
更改此对象的状态。
这样就可以更改ArrayList
中的对象。
答案 1 :(得分:2)
除基本类型外,所有变量都存储引用,而不是值。
第一个例子
Integer i = 6;
创建一个新的Integer
对象(我们称之为 I1 )并在i
ArrayList<Integer> ar = ArrayList<Integer>();
ar.add(i);`
创建ArrayList
,并在其中存储对 I1 的引用
i = 8;
创建一个新的(不同的)Integer
对象(我们称之为 I2 )并在i
现在,i
= I2 ,ar.get(0)
= I1
第二个例子
MyC myc = new MyC();
创建一个新的MyC
(让我们称之为 C )并在myc
myc.i = 6;
创建一个新的Integer
对象(我们称之为 I1 )并在 C 中存储对它的引用。i
ArrayList<MyC> ar = ArrayList<MyC>();
ar.add(myc);
创建ArrayList
,并在其中存储对 C 的引用。
myc.i = 8
创建一个新的Integer
对象(我们称之为 I2 )并在 C 中存储对它的引用。i
所以现在myc
= C ,myc.i
= I2 ,ar.get(0)
= C ,因此ar.get(0).i
= I2 。
没有任何内容引用 I1 ,它将被垃圾收集。
答案 2 :(得分:1)
这是因为编译器将i = 8
转换为i = new Integer(8)
,因为i
属于Integer
类型,而不是int
,因此您有2个引用现在。在第二个示例中,仍有一个参考引用myc
和ar
的第一个元素。
正如Sotirios在评论中所指出的,如果i
是原始的,你将得到相同的结果。但由于原因略有不同:
int i = 6;
ArrayList<Integer> ar = ArrayList<Integer>();
ar.add(i);
i = 8; // changes not a ref, but value on stack
System.out.println(ar.get(0)); // prints out 6
此处您没有两个引用,只有一个(在Integer
内自动装箱ar
)。
答案 3 :(得分:1)
Integer
是基本类型int
的对象包装器。
为了将它们存储在Collection
中,例如List<Integer> list = new ArrayList<Integer>()
,存储的元素类型必须是Object的子类。因此,它们通过引用存储,因为所有对象都存储为引用(并且所有方法都按值接收引用,请参阅Parameter passing in Java)
重要的是要注意
的情况List<Integer> list = new ArrayList<Integer>();
list.add(5);
int number = list.get(0);
System.out.println("" + number);
5可用于添加数字的原因是因为自动装箱。从列表中获取数字时,它还隐式调用.intValue()并将包装器的值作为基本int返回。然后在println()函数中,将数字隐式地装入Integer,然后调用toString()。
答案 4 :(得分:0)
Java中的所有变量都是引用堆上存在的对象的引用。
包装类(例如Integer)是特殊情况。那些实现Flyweight模式并且是不可变的。
答案 5 :(得分:0)
将i
指向另一个对象不会改变(原始)对象。这对于原语来说并不特殊。假设您有List<List<Object>>
或List<List<String>>
:
List<List<String>> wrapper = new ArrayList<List<String>>();
List<String> l1 = new ArrayList<String>();
wrapper.add(l1);
l1 = new ArrayList<String>();
l1.add("hello");
for(List<String> list : wrapper)
{
for(String string : list)
{
System.out.println(string);
}
}
如果你现在迭代wrapper
,你会发现它包含1个空列表。这相当于你的第一个例子。你的第二个例子如下:
List<List<String>> wrapper = new ArrayList<List<String>>();
List<String> l1 = new ArrayList<String>();
wrapper.add(l1);
l1.add("hello");
for(List<String> list : wrapper)
{
for(String string : list)
{
System.out.println(string);
}
}
在这种情况下,wrapper
现在包含1个列表,其中包含一个值。