5

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

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]

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

4

6 回答 6

10

该语句j=i;将引用分配为j与 相同的引用i。现在两者都i引用j同一个ArrayList对象。通过这两个引用可以简单地看到第 0 个索引的删除。

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

j = new ArrayList<Integer>(i);

(这是一个浅拷贝,所以列表仍然引用相同的元素。)

于 2013-10-24T17:49:45.210 回答
1

采用

j = new ArrayList<>(i);

或者

Collections.copy(j, i);

创建副本。

j = i你只需要j指出(i它被称为参考)。这适用于所有涉及对象的赋值(不是原始类型,如intor float

于 2013-10-24T17:51:06.400 回答
1

对象没有被克隆,只是添加了一个额外的对象引用。由于 ArrayList 不是不可变的,因此对对象的任何更改都会反映在两个对象引用中。

于 2013-10-24T17:52:01.827 回答
0

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

原语按你说的工作。如果您说i=5; j=i; i=6,则j仍将设置为 5。

于 2013-10-24T17:53:16.587 回答
0

您使用 ; 为 j 创建了一个记忆阶段 j = new ArrayList<>();
但是后来你说让 j 指的是 i 的记忆阶段。所以在 j=i 之后;i 或 j 上的任何更改都会影响它们。因为它们引用了相同的对象。

于 2013-10-24T17:54:36.950 回答
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));

比较两个值是否相同,这意味着 afterj=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
于 2013-10-24T18:03:48.357 回答