为什么一个arraylist在修改它的副本时会改变

时间:2013-10-24 17:48:24

标签: java

它可能是一个非常简单的但它仍然让我感到困惑!

import java.util.ArrayList;

public class Sample {
    ArrayList<Integer> i = new ArrayList<>();
    ArrayList<Integer> j = new ArrayList<>();

    /**
     * @param args
     */
    public static void main(String[] args) {
        new Sample().go();
    }

    private void go() {

        i.add(1);
        i.add(2);
        i.add(3);

        j=i;

        i.remove(0);


        System.out.println(i + "asd" + j);
    }

}

我试图打印它:

[2, 3]asd[2, 3]

当我改变时,为什么j会改变?但是不会发生原语!

6 个答案:

答案 0 :(得分:8)

语句j=i;将引用j指定为与i相同的引用。现在,ij都引用了相同的ArrayList对象。通过两个引用都可以看到删除第0个索引。

如果您希望删除i中的项目不会影响j中的列表,请创建列表的副本,而不是分配引用:

j = new ArrayList<Integer>(i);

(它是一个浅的副本,因此列表仍然引用相同的元素。)

答案 1 :(得分:1)

使用

j = new ArrayList<>(i);

Collections.copy(j, i);

创建副本。

使用j = i,您只需ji(称为参考号)。这适用于涉及对象的所有分配(不是intfloat等基本类型

答案 2 :(得分:1)

未克隆对象,仅添加了其他对象引用。由于ArrayList不是不可变的,因此对象的任何更改都会反映在对象引用中。

答案 3 :(得分:0)

对象和原语的工作方式有所不同。可以将i之类的对象视为该对象的名称。当你说j=i你告诉JVM时“忘记我说的其他ArrayList被称为j;从现在开始,当我提到j时,我的意思是这个ArrayList也可以被称为i。实际上,这正是发生的事情:在该行之后,两个变量都引用同一个对象。

原始人就像你说的那样工作。如果您说i=5; j=i; i=6,则j仍会设为5。

答案 4 :(得分:0)

你为j创建了一个内存阶段; j = new ArrayList&lt;&gt;();
但是你说让j引用我的内存阶段。所以在j = i之后; i或j上的任何变化都将影响它们。因为它们引用了相同的对象。

答案 5 :(得分:0)

让我以下列方式为您做到这一点:

ArrayList<Integer> i = new ArrayList<>();
ArrayList<Integer> j = new ArrayList<>();

// checking hash code before j = i;
System.out.println(System.identityHashCode(i));
System.out.println(System.identityHashCode(j));

j = i;

// checking hash code after j = i;
System.out.println(System.identityHashCode(i));
System.out.println(System.identityHashCode(j));

比较两个值是否相同,这意味着j=i; ArrayList j现在指向ArrayList i

在我的机器上o / p是:

30269696 //hashCode of i
24052850 //hashCode of j before j = i;

30269696 //hashCode of i and j are same after j = i that means they are pointing to same reference and hence change in one reflects on the other.
30269696