java集合存储值还是引用?

java集合存储值还是引用?,java,collections,reference,Java,Collections,Reference,Java初学者问题:当我 Integer i = 6; ArrayList<Integer> ar = ArrayList<Integer>(); ar.add(i); 然后执行myc.i=8,ar.get(0)返回8 您能解释一下这种行为吗?Java中的所有变量都是引用堆中存在的对象的引用 包装类(例如Integer)是特殊情况。这是因为编译器将i=8转换为i=new Integer(8),因为i是Integer类型,而不是int,所以现在有2个引用。在第二个示例中,

Java初学者问题:当我

Integer i = 6;
ArrayList<Integer> ar = ArrayList<Integer>();
ar.add(i);
然后执行
myc.i=8
ar.get(0)
返回
8


您能解释一下这种行为吗?

Java中的所有变量都是引用堆中存在的对象的引用


包装类(例如Integer)是特殊情况。这是因为编译器将
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
inti=6;
ArrayList ar=ArrayList();
ar.add(i);
i=8;//更改的不是ref,而是堆栈上的值
System.out.println(ar.get(0));//打印出6

这里没有两个引用,只有一个引用(在
ar
中指向自动装箱的
Integer

Integer
是围绕
int
基本类型的对象包装器

为了将它们存储在
集合中
例如
List List=new ArrayList()
,存储的元素类型需要是Object的子类。因此,它们通过引用存储,因为所有对象都存储为引用(并且所有方法都通过值接收引用,请参见)

需要注意的是,在以下情况下:

List<Integer> list = new ArrayList<Integer>();
list.add(5);
int number = list.get(0);
System.out.println("" + number);
List List=new ArrayList();
增加(5);
int number=list.get(0);
系统输出打印项次(“+编号);

之所以可以使用5来添加数字,是因为自动装箱。当您从列表中获取数字时,它还隐式调用.intValue(),并将包装器的值作为原始int返回。然后在println()函数中,数字隐式装箱为整数,然后调用toString()。

指向不同的对象不会改变(原始)对象。这对于基本体来说并不特殊。假设您有一个
列表
列表


在本例中,
包装器现在包含一个列表,其中有一个值。

正如一些答案所说,问题与自动装箱无关

在第一个示例中,创建一个整数并将其放入
ArrayList
中。 然后更改指向整数的指针,使
i
指向另一个整数。 这不会影响
ArrayList
的整数

在第二个示例中,创建一个对象并将其放入
ArrayList
。 然后通过
myc.i=8
更改此对象的状态。
通过这种方式,
ArrayList
中的对象将被更改。

除原语类型外,所有变量都存储引用,而不是值

第一个示例

Integer i = 6;
MyC myc = new MyC();
创建一个新的
Integer
对象(称之为I1),并将对它的引用存储在
i

ArrayList<Integer> ar = ArrayList<Integer>();
ar.add(i);`
ArrayList<MyC> ar = ArrayList<MyC>();
ar.add(myc);
创建一个新的(不同的)
Integer
对象(称之为I2),并将对它的引用存储在
i

ArrayList<Integer> ar = ArrayList<Integer>();
ar.add(i);`
ArrayList<MyC> ar = ArrayList<MyC>();
ar.add(myc);
现在,
i
=I2
ar.get(0)
=I1

第二个示例

Integer i = 6;
MyC myc = new MyC();
创建一个新的
MyC
(我们称之为C),并将对的引用存储在
MyC

myc.i = 6;
创建一个新的
Integer
对象(称之为I1),并在C
i
中存储对它的引用

ArrayList<Integer> ar = ArrayList<Integer>();
ar.add(i);`
ArrayList<MyC> ar = ArrayList<MyC>();
ar.add(myc);
创建一个新的
Integer
对象(称之为I2),并将对它的引用存储在C
i

ArrayList<Integer> ar = ArrayList<Integer>();
ar.add(i);`
ArrayList<MyC> ar = ArrayList<MyC>();
ar.add(myc);
所以现在
myc
=C
myc.i
=I2
ar.get(0)
=C,因此
ar.get(0).i
=I2


没有任何内容引用I1,它将被垃圾收集。

您会被自动装箱弄糊涂
i=8
比i是整数时看起来要复杂一些。这实际上是一个非常复杂的问题,尽管它看起来非常简单。欢迎大家关注自动装箱。
ar.get(0)
不会返回8
ar.get(0)。i
将返回8。自动装箱与此无关。问题是指向一个不同的对象而不是变异一个对象。@BrettOkken w/o自动装箱将没有“不同的对象”可指向,堆栈上将有一个基元
int
。对,因为您将原始ArrayList存储在包装器中,然后只需修改变量的引用。但这实际上并不是存储在包装器中的原始ArrayList。我认为这不是自动装箱的问题。在第一个示例中,指向i的指针在插入后发生了更改,在第二个示例中,对象myc本身也发生了更改。我觉得您的回答误导了读者,让他们认为如果
i
int
的话,结果会不同。您说得对,结果是一样的。更新答案。