java 中的浅拷贝?
Shallow copy in java?
就好像我们将预定义列表传递给新的 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));
}
}
它给了我越界异常.. 为什么?
通过做:
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
这只是复制引用。
调用该构造函数将创建一个引用相同项目的新列表,但它不会得到相同列表的支持。因此,您可以在不影响旧列表的情况下在新列表中添加和删除。但是,如果您有一些数据对象,那么无论您在哪个列表中访问它们,它们仍然会被操纵。
浅拷贝意味着它仍然会在单独的内存位置复制列表,但如果列表中有更多集合,它将复制对这些集合的引用,而不是递归复制。这就是为什么您会收到越界错误的原因 - 3 仅添加到第一个列表而不是第二个列表,因为它们现在作为两个完全独立的列表存在。您正在使用的复制构造函数在 the API 中描述为:
(ArrayList(Collection<? extends E> c)
:
Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator.
如果您只想复制引用,可以使用赋值运算符而不是复制构造函数:
List<Integer> list2 = list1;
List<Integer> list2 = (list);
然后添加到list中,作用在list2中,也就是Shallow-Copy,如果用Constructor,就相当于Deep-copy...
来自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;
就好像我们将预定义列表传递给新的 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));
}
}
它给了我越界异常.. 为什么?
通过做:
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
这只是复制引用。
调用该构造函数将创建一个引用相同项目的新列表,但它不会得到相同列表的支持。因此,您可以在不影响旧列表的情况下在新列表中添加和删除。但是,如果您有一些数据对象,那么无论您在哪个列表中访问它们,它们仍然会被操纵。
浅拷贝意味着它仍然会在单独的内存位置复制列表,但如果列表中有更多集合,它将复制对这些集合的引用,而不是递归复制。这就是为什么您会收到越界错误的原因 - 3 仅添加到第一个列表而不是第二个列表,因为它们现在作为两个完全独立的列表存在。您正在使用的复制构造函数在 the API 中描述为:
(ArrayList(Collection<? extends E> c)
: Constructs a list containing the elements of the specified collection, in the order they are returned by the collection's iterator.
如果您只想复制引用,可以使用赋值运算符而不是复制构造函数:
List<Integer> list2 = list1;
List<Integer> list2 = (list);
然后添加到list中,作用在list2中,也就是Shallow-Copy,如果用Constructor,就相当于Deep-copy...
来自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;