前言
这段时间在看《设计模式之禅》这本书,其中讲到了原型模式,可说老实话在此之前我从来没听说过还有这种模式的存在,是我孤陋寡闻了!在阅读了相关文章后,引出了深拷贝和浅拷贝,之前了解过这个知识点的,到现在完全没有印象了。就此,做出如下简述。
正文
在说深拷贝和浅拷贝之前先了解Java中的Cloneable接口
该接口与java.util.RandomAccess
接口一样,仅起标识作用。实现此接口并重写clone()
方法,即可实现类的拷贝功能。不管是深拷贝(非必须)还是浅拷贝都依赖于此接口。
浅拷贝
浅拷贝(Shallow Clone)从其名字大致可以了解其特性。在拷贝过程中,对于不同类型类型做出了区分,
- 对于基本数据类型拷贝值,进行值传递
- 对于引用数据类型只是进行了引用传递
通过实例代码查看执行结果:
@ToString
public class ShallowClone implements Cloneable {
private int age;
private List<String> list = new ArrayList<>();
public ShallowClone() {
}
public ShallowClone(int age, List<String> list) {
this.age = age;
this.list = list;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<String> getList() {
return list;
}
public void setList(String str) {
this.list.add(str);
}
@Override
protected ShallowClone clone() throws CloneNotSupportedException {
return (ShallowClone) super.clone();
}
public static void main(String[] args) throws CloneNotSupportedException {
// 为shallowClone赋值
ShallowClone shallowClone = new ShallowClone();
shallowClone.setAge(12);
shallowClone.setList("123");
// clone后对新对象进行赋值
ShallowClone clone = shallowClone.clone();
// 如果新对象不设置age属性,age还是12
clone.setAge(11);
// 因为对引用类型是不进行拷贝,所以对list的两次添加数据会保存在一起
clone.setList("456");
// ShallowClone(age=12, list=[123, 456])
System.out.println(shallowClone.toString());
// ShallowClone(age=11, list=[123, 456])
System.out.println(clone.toString());
}
}
拷贝过程如下图所示
在调用了clone()
方法后再赋值,对于age
字段来说并没有影响,但对于list
就相当于执行了两次add()
操作。
深拷贝
深拷贝(Deep Clone)对比于前者的区别在于对引用类型的复制,会创建一个新对象,并复制其内容。这里使用Hutool中的深拷贝方法ObjectUtil.cloneByStream()
,实现Serializable
接口即可,通过序列化完成拷贝
@ToString
public class DeepClone implements Serializable {
private static final long serialVersionUID = -174641130567660496L;
private int age;
private List<String> list = new ArrayList<>();
public DeepClone() {
}
public DeepClone(int age, List<String> list) {
this.age = age;
this.list = list;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<String> getList() {
return list;
}
public void setList(String str) {
this.list.add(str);
}
public static void main(String[] args) throws CloneNotSupportedException {
// 初始化原对象
DeepClone deepClone = new DeepClone();
deepClone.setAge(12);
deepClone.setList("123");
// 执行深拷贝
DeepClone clone = ObjectUtil.cloneByStream(deepClone);
clone.setAge(11);
clone.setList("456");
clone.setList("456");
clone.setList("456");
// DeepClone(age=12, list=[123])
System.out.println(deepClone.toString());
// DeepClone(age=11, list=[123, 456, 456, 456]) 对clone的改变并没有影响deepClone
System.out.println(clone.toString());
}
}
这里使用HuTool中的深拷贝方法ObjectUtil.cloneByStream()
,其底层的执行逻辑如下图