解决某些entity大量属性的重用率很高,手动设置过于繁琐且无必要的问题。
先看原型设计模式之浅拷贝
//原型模式
public class Prototype {
public static void main (String[] args) throws CloneNotSupportedException {
Report report = new Report();
report.setId (1);
report.setName("mary");
report.setAge(80);
System.out.println(report.toString());
//当Report的参数很多,重复属性又很大时,先clone,再修改差异值,就节约很多时间。
Report report1 = (Report) report.clone();
report1.setName("Tom");
System.out.println(report1.toString());
Report report2 = (Report) report.clone();
System.out.println(report == report2);
}
}
@Data
class Report implements Cloneable {
private int id;
private String name;
private int age;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
优点:clone直接得到一个模板原型对象,方便,clone是直接复制内存中的2进制信息,效率很高。
ps:report == report2 FALSE 地址不相等。所以复制会破坏单例对象,单例对象应该禁止克隆。
缺点:直接上代码
//原型模式
public class Prototype {
public static void main (String[] args) throws CloneNotSupportedException {
Report report = new Report();
report.setId (1);
report.setName("mary");
report.setAge(80);
report.setCreatTime(new Date());
System.out.println(report.toString());
//当Report的参数很多,重复属性又很大时,先clone,再修改差异值,就节约很多时间。
Report report1 = (Report) report.clone();
report1.setName("Tom");
System.out.println(report1.toString());
Report report2 = (Report) report.clone();
System.out.println(report == report2);
//浅拷贝的弊端:属性对象指向堆中同一对象,一个修改,全部修改。
report2.getCreatTime().setTime(0);
System.out.println("report1:"+report1.toString());
System.out.println("report2:"+report2.toString());
}
}
@Data
class Report implements Cloneable {
private int id;
private String name;
private int age;
private Date creatTime;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
输出结果
Report(id=1, name=mary, age=80, creatTime=Thu Sep 24 11:37:38 CST 2020)
Report(id=1, name=Tom, age=80, creatTime=Thu Sep 24 11:37:38 CST 2020)
false
report1:Report(id=1, name=Tom, age=80, creatTime=Thu Jan 01 08:00:00 CST 1970)
report2:Report(id=1, name=mary, age=80, creatTime=Thu Jan 01 08:00:00 CST 1970)
Process finished with exit code 0
report2.getCreatTime().setTime(0);只是设置了report2的时间,但是report1的时间也被修改了。
属性对象指向堆中同一对象,一个修改,全部修改。下图的Object C 就是Date
解决这个问题,就有了深克隆,在克隆时,对于时间也克隆一份。
class Report implements Cloneable {
private int id;
private String name;
private int age;
private Date creatTime;
@Override
protected Object clone() throws CloneNotSupportedException {
Report report = (Report) super.clone();
//克隆一份date 让克隆前后的两个Date对象指向不同的堆中对象
Date date = (Date) report.getCreatTime().clone();
report.setCreatTime(date);
return report;
}
}
再次运行的结果
Report(id=1, name=mary, age=80, creatTime=Thu Sep 24 11:51:05 CST 2020)
Report(id=1, name=Tom, age=80, creatTime=Thu Sep 24 11:51:05 CST 2020)
false
report1:Report(id=1, name=Tom, age=80, creatTime=Thu Sep 24 11:51:05 CST 2020)
report2:Report(id=1, name=mary, age=80, creatTime=Thu Jan 01 08:00:00 CST 1970)
Process finished with exit code 0
可以看出report1和report2的时间不一样了。深拷贝成功。下面原理图
关于深克隆,以上实现方式,对于属性的增减,也很麻烦,有个一劳永逸且快速的方法,序列化的方式深克隆,文件流写入内存,请勿写到文件中。
//深拷贝 方式2 用序列化 推荐使用.
@Override
protected Object clone() throws CloneNotSupportedException {
try {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(this);//谁调用此clone方法,就序列化谁。
oos.close();
byte[] bb = out.toByteArray();
InputStream is = new ByteArrayInputStream(bb);
ObjectInputStream ois = new ObjectInputStream(is);
Object o = ois.readObject();
ois.close();
return o;
} catch (Exception e){
throw new RuntimeException(e);
}
}
如果你指定F://aa.txt 那其他环境无法运行,别人没有F盘,或者Linux执行等。