深拷贝的介绍
- 复制对象的所有基本数据类型的成员变量值
- 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象.也就是说,对象进行深拷贝要对整个对象进行拷贝
- 深拷贝实现方式1: 重写clone()方法实现深拷贝
- 深拷贝实现方式2: 通过对象序列化实现深拷贝
深拷贝实践
第一种
DeepCloneableTarget
package com.atguigu.prototype.deepclone;
import java.io.Serializable;
public class DeepCloneableTarget implements Serializable,Cloneable {
/*
*
* */
private static final long serialVersionUID = 1L;
private String cloneName;
private String cloneClass;
public DeepCloneableTarget(String cloneName, String cloneClass) {
this.cloneName = cloneName;
this.cloneClass = cloneClass;
}
public DeepCloneableTarget() {
super();
}
// 因为该类的属性都是String, 因此我们这里使用默认的clone方法完成即可
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
DeepCloneableTarget
package com.atguigu.prototype.deepclone;
import java.io.Serializable;
public class DeepProtoType implements Serializable,Cloneable {
public String name; // String 属性
public DeepCloneableTarget deepCloneableTarget; // 引用类型属性
public DeepProtoType() {
super();
}
// 深拷贝 -- 方式1 使用clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Object deep = null;
// 这里完成对基本数据类型(属性) 和String 的克隆
deep = super.clone();
// 对引用类型的属性,进行单独处理
// 先创建,转换子类类型
DeepProtoType deepProtoType = (DeepProtoType) deep;
deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();
return deepProtoType;
}
/*
* 问题: 这样不会递归拷贝么?
* */
}
Clinet
package com.atguigu.prototype.deepclone;
public class Clinet {
public static void main(String[] args) throws CloneNotSupportedException {
DeepProtoType p = new DeepProtoType();
p.name = "松江";
p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛");
//方式1 完成深拷贝
DeepProtoType p2 = (DeepProtoType) p.clone();
System.out.println(p);
System.out.println(p.name);
System.out.println(p.deepCloneableTarget);
System.out.println(p2);
System.out.println(p2.name);
System.out.println(p2.deepCloneableTarget);
/*
com.atguigu.prototype.deepclone.DeepProtoType@1540e19d
松江
com.atguigu.prototype.deepclone.DeepCloneableTarget@677327b6
com.atguigu.prototype.deepclone.DeepProtoType@14ae5a5
松江
com.atguigu.prototype.deepclone.DeepCloneableTarget@7f31245a
Process finished with exit code 0
* */
/*
* todo 这种方式 就是可以 实现深拷贝
* 说白了就是,在里面 提取出来属性对象, 单独进行拷贝
* */
}
}
第二种
DeepProtoType
package com.atguigu.prototype.deepclone;
import java.io.*;
public class DeepProtoType implements Serializable,Cloneable {
public String name; // String 属性
public DeepCloneableTarget deepCloneableTarget; // 引用类型属性
public DeepProtoType() {
super();
}
// 深拷贝 -- 方式2 通过对象的序列化实现(推荐)
public Object deepClone(){
// 创建流对象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
// 序列化
bos = new ByteArrayOutputStream();
// 吧这个字节数组输出流换成了对象输出流
oos = new ObjectOutputStream(bos);
// 把当前这个对象以对象流的方式输出
oos.writeObject(this);
// 反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
// 读进来就相当于把我们这个对象进行了克隆
ois = new ObjectInputStream(bis);
// ois就读到了原来序列化出去的这个对象
DeepProtoType copyObj = (DeepProtoType)ois.readObject();
// 我用序列化这个特点,把你关联的引用的输出出去,读回来后就相当云拷贝了
return copyObj;
// 我们这波操作就是充分利用我们的序列化和饭序列化,
// 把当前对象以对象流的方式输出和读回来,就不用一个一个来搞了
} catch (IOException e) {
e.printStackTrace();
return null;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
// 关闭已经打开的流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (IOException e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
}
return null;
}
}
DeepCloneableTarget
package com.atguigu.prototype.deepclone;
import java.io.Serializable;
public class DeepCloneableTarget implements Serializable,Cloneable {
/*
*
* */
private static final long serialVersionUID = 1L;
private String cloneName;
private String cloneClass;
public DeepCloneableTarget(String cloneName, String cloneClass) {
this.cloneName = cloneName;
this.cloneClass = cloneClass;
}
public DeepCloneableTarget() {
super();
}
// 因为该类的属性都是String, 因此我们这里使用默认的clone方法完成即可
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Clinet
package com.atguigu.prototype.deepclone;
public class Clinet {
public static void main(String[] args) throws CloneNotSupportedException {
DeepProtoType p = new DeepProtoType();
p.name = "松江";
p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛");
// 方式2 完成深拷贝
DeepProtoType p2 = (DeepProtoType) p.deepClone();
System.out.println(p);
System.out.println(p.name);
System.out.println(p.deepCloneableTarget);
System.out.println(p2);
System.out.println(p2.name);
System.out.println(p2.deepCloneableTarget);
/*
com.atguigu.prototype.deepclone.DeepProtoType@330bedb4
松江
com.atguigu.prototype.deepclone.DeepCloneableTarget@2503dbd3
com.atguigu.prototype.deepclone.DeepProtoType@4f3f5b24
松江
com.atguigu.prototype.deepclone.DeepCloneableTarget@15aeb7ab
Process finished with exit code 0
* */
// 推荐第2中
}
}
原型模式的注意事项和细节
- 创建新的对象比较复杂的时候,可以利用原型模式简化对象的创建过程,同时也能够提高效率
- 不用重新初始化对象,而是动态地获得对象运行时的状态
- 如果原始对象发生变化(增加或者减少属性),其他克隆对象的也会发生相应的编号,无需修改代码
- 在实现深克隆的时候可能需要比较复杂的代码
- 缺点: 需要为每一个类配备一个克隆方法,这对全新的类来说,不是很难,但是对已经有的类进行改造的时候,需要修改其源码,这就违背了ocp开放封闭原则,这点要注意一下.