什么是深拷贝和浅拷贝

image-20240904223220398

1. 定义

  • 浅拷贝(Shallow Copy):浅拷贝是在复制对象时,仅复制对象本身及其包含的基本数据类型字段,但对于对象中引用类型的字段,只复制引用地址,而不会复制引用对象本身。换句话说,浅拷贝后的新对象与原对象共享引用类型字段所指向的对象。
  • 深拷贝(Deep Copy):深拷贝则不仅复制对象本身及其基本数据类型字段,还会递归地复制所有引用类型字段所指向的对象,创建出这些对象的副本。深拷贝后的新对象与原对象完全独立,修改一个不会影响另一个。

2. 示例代码

为了更好地理解深拷贝和浅拷贝的区别,以下是一个包含浅拷贝和深拷贝的Java示例。

假设我们有一个包含引用类型字段的类Person,该类包含name(基本类型)和address(引用类型)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
class Address implements Cloneable {
String city;

public Address(String city) {
this.city = city;
}

@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}

@Override
public String toString() {
return city;
}
}

class Person implements Cloneable {
String name;
Address address;

public Person(String name, Address address) {
this.name = name;
this.address = address;
}

// 浅拷贝
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}

// 深拷贝
protected Person deepClone() throws CloneNotSupportedException {
Person clonedPerson = (Person) super.clone();
clonedPerson.address = (Address) address.clone(); // 递归克隆Address对象
return clonedPerson;
}

@Override
public String toString() {
return name + " lives in " + address;
}
}

public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Address address = new Address("New York");
Person person1 = new Person("John", address);

// 浅拷贝
Person shallowCopyPerson = (Person) person1.clone();
// 深拷贝
Person deepCopyPerson = person1.deepClone();

// 浅拷贝测试
System.out.println("Before modification:");
System.out.println("Original: " + person1); // 输出 John lives in New York
System.out.println("Shallow Copy: " + shallowCopyPerson); // 输出 John lives in New York

// 修改引用类型字段的值
address.city = "San Francisco";

System.out.println("After modification:");
System.out.println("Original: " + person1); // 输出 John lives in San Francisco
System.out.println("Shallow Copy: " + shallowCopyPerson); // 输出 John lives in San Francisco

// 深拷贝测试
System.out.println("Deep Copy: " + deepCopyPerson); // 输出 John lives in New York
}
}

3. 运行结果

运行上述代码时,输出如下:

1
2
3
4
5
6
7
8
9
Before modification:
Original: John lives in New York
Shallow Copy: John lives in New York

After modification:
Original: John lives in San Francisco
Shallow Copy: John lives in San Francisco

Deep Copy: John lives in New York

4. 结果分析

  • 浅拷贝:在浅拷贝的示例中,当我们修改原对象person1address.city字段时,浅拷贝对象shallowCopyPersonaddress.city字段也跟着改变了。这是因为浅拷贝只复制了address字段的引用地址,因此原对象和浅拷贝对象共享同一个Address实例。
  • 深拷贝:在深拷贝的示例中,deepCopyPerson拥有与原对象person1独立的Address实例。因此,当我们修改原对象的address.city字段时,深拷贝对象deepCopyPersonaddress.city字段保持不变,这说明它们完全独立。

5. 小结

  • 浅拷贝:复制对象时,不复制对象中引用类型字段指向的对象,拷贝的对象与原对象共享这些引用类型的字段。
  • 深拷贝:复制对象时,递归地复制对象中引用类型字段指向的对象,拷贝的对象与原对象完全独立。

浅拷贝适用于对象较为简单且不涉及深层次依赖的场景,而深拷贝则适用于需要完整复制对象及其依赖的复杂场景。