最初的写法 在类中实现克隆方法 原型模式
可以重写equals和hashcode 反序列化出来的对象地址是不同的equals
User类
为了测试深拷贝,要在需要拷贝的类中加入引用类型
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class User implements Serializable {
private String username;
private String password;
}
Prototype类
package design.prototype;
import lombok.*;
import java.io.*;
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@ToString
public class Prototype implements PrototypeSup, Serializable {
private String name;
private User user;
//序列化操作
@Override
public Object clone() {
//深拷贝
//创建流对象 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);
Prototype prototype = (Prototype) ois.readObject();
return prototype;
} catch (Exception e) {
e.printStackTrace();
return null; } finally {
//关闭流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e2) {
System.out.println(e2.getMessage());
}
}
}
}
PrototypeSup类
public interface PrototypeSup {
public Object clone();
}
测试类
public static void main(String[] args) {
//测试开始
User user = new User("zhangsan","132");
//定义一个我们要拷贝的目标
Prototype prototype = new Prototype("原型实例",user);
//克隆
Prototype proClone = (Prototype) prototype.clone();
Prototype proClone3 = (Prototype) prototype.clone();
System.out.println(proClone+" hashcode"+proClone.hashCode()+
"User"+proClone.getUser()+" hashcod"+proClone.getUser().hashCode());
System.out.println(proClone3+" hashcode"+proClone3.hashCode()+
"User"+proClone3.getUser()+" hashcod"+proClone3.getUser().hashCode());
}
运行结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N6aYFCgg-1666841383435)(file:///C:/Users/林巳洁/AppData/Roaming/marktext/images/2022-10-08-20-36-23-image.png?msec=1666841185120)]
第二种写法 将clone接口去除改成工具类 普通类想要克隆只需要序列化(实现序列化接口)就可以
public class ProTypeUtil{
//序列化操作
//传入想要拷贝的对象
//传入的clazz需要和data是一个类
public static <T> T ToClone(Object data,Class<T> clazz) {
//深拷贝
//创建流对象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(data); //当前这个对象以对象流的方式输出
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
T prototype=null;
if (clazz.isInstance(data)){
System.out.println("传入的class和类是相同的类型");
System.out.println(clazz);
prototype = (T)ois.readObject();
}
return prototype;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
//关闭流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e2) {
System.out.println(e2.getMessage());
}
}
}
}
将方法改成静态的 利用方法内的泛型以及多传入一个类型来解决问题
//测试开始
User user = new User("zhangsan","132");
//定义一个我们要拷贝的目标
Prototype prototype = new Prototype("原型实例",user);
//克隆
Prototype proClone = ProTypeUtil.ToClone(prototype,prototype.getClass());
Prototype proClone1 = ProTypeUtil.ToClone(prototype,Prototype.class);
Prototype proClone2 = prototype;
Prototype proClone3 = prototype ;
System.out.println(proClone+" hashcode"+proClone.hashCode()+"User"+proClone.getUser()+" hashcod"+proClone.getUser().hashCode());
System.out.println(proClone3+" hashcode"+proClone3.hashCode()+"User"+proClone3.getUser()+" hashcod"+proClone3.getUser().hashCode());
//地址不相同
System.out.println(proClone==proClone3);
System.out.println(proClone2==proClone2);
类的获取用 .class 和 getclass 都可以实现,
至此我们完成了利用一个工具类就可以深拷贝一个实例,因为利用序列化和反序列化的原理,需要为所有用到的类和引用类型添加接口,
反序列化
缺点是 性能消耗较大
原理参考文章[(33条消息) 设计模式-原型模式(克隆羊多利看了都说好)_吾仄lo咚锵的博客-CSDN博客_多利设计模式