简介
- 浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递的拷贝。
- 深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象并复制其内容,做到了真正完全的拷贝。
浅拷贝实现
以下场景中有两个类,一个是Parent,一个是Child:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class Parent implements Cloneable {
String parentName;
Child child;
public Parent(String parentName, Child child) {
this.parentName = parentName;
this.child = child;
}
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Child {
String childName;
public Child(String childName) {
this.childName = childName;
}
}
要实现浅拷贝,只需要让Parent实现Cloneable接口,并覆盖Object的clone()方法即可。以下为测试代码:1
2
3
4
5
6
7
8
9
10
11
12
13public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Parent parent1 = new Parent("parent name", new Child("child name"));
Parent parent2 = (Parent) parent1.clone();
System.out.println(parent1 == parent2);
System.out.println(parent1.parentName);
System.out.println(parent2.parentName);
System.out.println("==================");
System.out.println(parent1.child == parent2.child);
System.out.println(parent1.child.childName);
System.out.println(parent2.child.childName);
}
}
控制台输出:1
2
3
4
5
6
7false
parent name
parent name
==================
true
child name
child name
可以看出,浅拷贝确实创建了一个新的Parent对象,并且属性parentName的值也一模一样,但是对于为引用类型的属性child,实际上与之前引用的是同一个对象。
深拷贝实现
要实现深拷贝,常用的方案有以下两种:
- 序列化这个对象,再反序列化回来,就可以得到新的对象。
- 让属性也实现
Cloneable。
属性实现Cloneable
1 | public class Parent implements Cloneable { |
和之前的浅拷贝不同之处在于这里Child也实现了Cloneable,并覆盖了clone()方法,而Parent的clone()方法也有略微不同,在调用了clone()方法后还调用了属性child的clone()方法重新设置属性,从而实现完完全全的拷贝。
此时控制台输出如下:1
2
3
4
5
6
7false
parent name
parent name
==================
false
child name
child name
注意到此时原始对象和拷贝对象的child属性所引用的不再是同一个对象了。
序列化方式
1 | public class Parent implements Serializable { |
此时两个类都不需要再实现Cloneable接口并覆盖clone()方法了,但是它们都需要实现Serializable接口,并且在Parent的克隆方法中要实现序列化反序列化的逻辑,此时控制台输出如下:1
2
3
4
5
6
7false
parent name
parent name
==================
false
child name
child name