提问人:蔡纪轮 提问时间:12/18/2017 更新时间:8/14/2018 访问量:4122
Java 的 ArrayList 的复制构造函数是浅拷贝还是深拷贝?
Is the copy constructor of Java's ArrayList shallow copy or deep copy?
问:
长期以来,我一直对 Java 容器的复制构造函数是浅拷贝还是深拷贝感到困惑? 以下是我的理解: ints1、ints2、ints3 是引用,因此它们位于堆栈中。 inst1 指向堆中的某个对象,该对象包含位于堆栈中的三个匿名引用,它们分别指向 int 值为 0、1、2 的对象。
ints2 = ints1
因此,ints2 指向与 ints1 相同的对象。因此,更改 ints2 中引用指向的对象将影响 ints2 中的对象。
ints2.set(1,0+10)
将更改引用 ints1.get(0) 的对象。
ints3 = new ArrayList<>(ints1)
接下来是我的困惑。
如果 copy 构造函数是 shallow copy,那么尽管 ints1 和 ints3 指向不同的对象,但这两个对象具有相同的引用!因此,任何通过操作 ints1 中的引用来更改对象的操作都会更改 ints3,因为它们指向相同的对象。
如果 copy 构造函数是 deep copy,则 ints1 和 ints3 将保存不同的引用并指向不同的对象。那么 ints1 的变化不会影响 ints3 中的更改。
根据结果,复制构造函数似乎是深拷贝,而不是浅拷贝。
希望有人能纠正我,谢谢。
import java.util.*;
public class MyClass {
public static void main(String args[]) {
List<Integer> ints1 = new ArrayList<>(Arrays.asList(0,1,2));
System.out.println(ints1);
List<Integer> ints2 = ints1;
ints2.set(0,0+10);
System.out.println(ints1);
List<Integer> ints3 = new ArrayList<>(ints1);
ints3.set(1,1+10);
System.out.println(ints1);
}
}
result
[0, 1, 2]
[10, 1, 2]
[10, 1, 2]
答:
答案是:浅拷贝。看看这篇文章,它提供了有关该主题的更多详细信息:http://javarevisited.blogspot.co.uk/2014/03/how-to-clone-collection-in-java-deep-copy-vs-shallow.html?m=1
问题的关键在于,当您这样做时,您实际上是在更改存储在 中的引用。存储在 中的引用不受此影响。ints3.set(1, 1+10)
ints3[1]
ints1[1]
// Format
----------
| Value |
----------
Address
// Actual data
------ ------ ------- ------
| 1 | ...| 2 | ... | 3 | ...... | 42 |
------ ------ ------- ------
10 20 30 80
// ArrayList <Integer> a = new ArrayList <Integer> (Arrays.asList(1, 2, 3));
------ ------ ------ ------
| 100 | ---> | 10 | 20 | 30 |
------ ------ ------ ------
a 100 104 108
// ArrayList <Integer> b = new ArrayList <Integer> (a);
------ ------ ------ ------
| 200 | ---> | 10 | 20 | 30 |
------ ------ ------ ------
b 200 204 208
When you do:
a[1] = 42, it is equivalent to:
------ ------ ------ ------
| 100 | ---> | 10 | 80 | 30 |
------ ------ ------ ------
a 100 104 108
Note that this does not change b in any way.
另外,请查看以下代码。在这里,您可以看到它确实是浅拷贝,因为当您修改引用指向的值时,它会同时反映在 和 中。a
b
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
class Node {
int data;
String name;
Node(int data, String name) {
this.data = data;
this.name = name;
}
public String toString() {
return "{" + Integer.toString(data) + ", " + name + "}";
}
}
class ArrayListTest {
public static void main(String[] args) {
ArrayList <Node> a = new ArrayList <Node>();
Node n[] = new Node[5];
for(int i = 0; i < 5; i++) {
n[i] = new Node(i, Integer.toString(i));
}
a.add(n[0]);
a.add(n[1]);
a.add(n[2]);
System.out.println("Previously: ");
System.out.println("a = " + a.toString());
ArrayList <Node> b = new ArrayList <Node> (a);
System.out.println("b = " + b.toString());
// This does not affect b as b has aready made a copy of
// all the references in a different location.
a.add(n[3]);
n[2].data = 10;
n[2].name = "10";
System.out.println("\nCurrent: ");
System.out.println("a = " + a.toString());
System.out.println("b = " + b.toString());
}
}
评论
n[2]
a.set(1, n[0])
a
b
a.set(1, n[0])
a
b
b
a
b
a
b
a
b
评论