就像我们将预定义列表传递给新的ArrayList构造函数一样,它将SHALLOW-COPY该列表,这意味着对该列表的引用,因此,如果我们修改新列表,则更改也倾向于在旧列表上进行修改。这个程序不是这种情况....为什么?
public class testArrayList {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
List<Integer> list2 = new ArrayList<>(list);
list.add(3);
System.out.println(list2.get(2));
}
}
这给了我无限的例外。为什么?
答案 0 :(得分:2)
这样做:
List<Integer> list2 = new ArrayList<>(list);
您正在创建列表的副本。这是ArrayList
的构造函数代码的简化版本:
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// List copy is performed here!
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
您想要做的是:
List<Integer> list2 = list1
只需复制参考即可。
答案 1 :(得分:2)
调用该构造函数将创建一个引用相同项目的新列表,但不会由同一列表支持。因此,您可以在不影响旧列表的情况下添加和删除新列表。但是,如果您有一些数据对象,无论您在哪个列表中访问它们,这些对象仍将受到操纵。
答案 2 :(得分:0)
浅表副本意味着它仍将在单独的内存位置中复制列表,但是如果列表中还有其他集合,它将复制对它们的引用,而不是递归复制。这就是为什么会出现边界错误的原因-3仅添加到第一个列表中,而不添加到第二个列表中,因为它们现在作为两个完全独立的列表存在。您正在使用的副本构造函数在the API中描述为:
(ArrayList(Collection<? extends E> c)
: 构造一个包含指定集合元素的列表,其顺序由集合的迭代器返回。
如果您只想复制引用,则可以使用赋值运算符而不是复制构造函数:
List<Integer> list2 = list1;
答案 3 :(得分:0)
List<Integer> list2 = (list);
然后将其添加到列表中,它在list2(即浅拷贝)中起作用,如果您使用Constructor,则就像Deep-copy ...
答案 4 :(得分:0)
来自ArrayList.class
:
public ArrayList(Collection<? extends E> c) {
this.elementData = c.toArray();
if ((this.size = this.elementData.length) != 0) {
if (this.elementData.getClass() != Object[].class) {
this.elementData = Arrays.copyOf(this.elementData, this.size, Object[].class);
}
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
这是实现ArrayList
构造函数的方式。复制所有元素,并创建新的ArrayList。如果您想将引用复制到旧列表,则应执行以下操作:
List<Integer> list2 = list;
答案 5 :(得分:-1)
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
List<Integer> list1 = list;
list1.add(3);
System.out.println(list1.get(2)
);