学习设计模式之原型模式时,认识了深复制与浅复制。
java中的Object类中,有一个clone()方法,它用于生成一个新的对象,当然如果我们要调用这个方法,java要求我们的类必须先实现一个Cloneable接口,此接口没有定义任何方法,但要是不实现,在clone()的时候,会抛出cloneNotSupportedException异常。
java 的克隆是浅克隆,碰到对象引用的时候,克隆出来的对象和原对象中的引用将指向同一个对象。通常实现深克隆的方法是将对象进行序列化,然后再进行反序列化。
先看浅拷贝:
public class WorkExperience {
private String workDate;
private String company;
public String getWorkDate() {
return workDate;
}
public void setWorkDate(String workDate) {
this.workDate = workDate;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
}
-----------------------
public class Prototype implements Cloneable{
private String name;
private String sex;
private String age;
private WorkExperience work;//这是引用类型
public Prototype(String name) {
this.name = name;
work = new WorkExperience();
}
//设置个人信息
public void serPersonalInfo(String sex,String age) {
this.sex = sex;
this.age = age;
}
//设置工作经历
public void setWorkExperience(String workDate,String company) {
work.setWorkDate(workDate);
work.setCompany(company);
}
//显示
public void Display() {
System.out.println("姓名:"+name+" 性别:"+sex+" 年龄:"+age);
System.out.println("工作经历:"+work.getWorkDate()+"-"+work.getCompany());
}
public Object Clone() throws CloneNotSupportedException {
return this.clone();
}
}
----------------------
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Prototype type1 = new Prototype("大牛");
type1.serPersonalInfo("男", "29");
type1.setWorkExperience("2010-2015", "阿里");
Prototype type2 = (Prototype)type1.Clone();
type1.setWorkExperience("2016-2020", "腾讯");
Prototype type3 = (Prototype)type1.Clone();
type3.setWorkExperience("2021-2030", "百度");
type1.Display();
System.out.println("---------------");
type2.Display();
System.out.println("----------------");
type3.Display();
}
}
运行结果:
姓名:大牛 性别:男 年龄:29
工作经历:2021-2030-百度
---------------
姓名:大牛 性别:男 年龄:29
工作经历:2021-2030-百度
----------------
姓名:大牛 性别:男 年龄:29
工作经历:2021-2030-百度
可以看到运行结果中,三次工作经历都是最后一次设置的值,这就是浅拷贝,被复制对象的所有变量都含有与原来对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。
深复制把引用对象的变量指向复制过的新对象,而不是原有的被引用的对象。
深拷贝实现:
public class WorkExperience implements Cloneable {
private String workDate;
private String company;
public String getWorkDate() {
return workDate;
}
public void setWorkDate(String workDate) {
this.workDate = workDate;
}
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
//工作经历类也实现Cloneable接口,调用object的clone()方法
public Object Clone() throws CloneNotSupportedException {
return this.clone();
}
}
------------------------------
public class Prototype implements Cloneable{
private String name;
private String sex;
private String age;
private WorkExperience work;
public Prototype(String name) {
this.name = name;
work = new WorkExperience();
}
//提供Clone方法调用的私有构造函数,以便克隆“工作经历”的数据
private Prototype(WorkExperience work) throws CloneNotSupportedException {
this.work = (WorkExperience)work.Clone();
}
//设置个人信息
public void serPersonalInfo(String sex,String age) {
this.sex = sex;
this.age = age;
}
//设置工作经历
public void setWorkExperience(String workDate,String company) {
work.setWorkDate(workDate);
work.setCompany(company);
}
//显示
public void Display() {
System.out.println("姓名:"+name+" 性别:"+sex+" 年龄:"+age);
System.out.println("工作经历:"+work.getWorkDate()+"-"+work.getCompany());
}
// public Object Clone() throws CloneNotSupportedException {
// return this.clone();
// }
//调用私有的构造方法,让“工作经历”克隆完成,然后在给Prototype对象的相关字段赋值,最终返回一个深复制的简历对象
public Object Clone() throws CloneNotSupportedException {
Prototype obj = new Prototype(this.work);
obj.name = this.name;
obj.sex = this.sex;
obj.age = this.age;
return obj;
}
}
---------------------------------
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Prototype type1 = new Prototype("大牛");
type1.serPersonalInfo("男", "29");
type1.setWorkExperience("2010-2015", "阿里");
Prototype type2 = (Prototype)type1.Clone();
type2.setWorkExperience("2016-2020", "腾讯");
Prototype type3 = (Prototype)type1.Clone();
type3.serPersonalInfo("女","16");
type3.setWorkExperience("2021-2030", "百度");
type1.Display();
System.out.println("---------------");
type2.Display();
System.out.println("----------------");
type3.Display();
}
}
运行结果:
姓名:大牛 性别:男 年龄:29
工作经历:2010-2015-阿里
---------------
姓名:大牛 性别:男 年龄:29
工作经历:2016-2020-腾讯
----------------
姓名:大牛 性别:女 年龄:16
工作经历:2021-2030-百度