深度讲解23种设计模式,力争每种设计模式都刨析到底。废话不多说,开始第二种设计模式 - 原型。
一、为什么有原型模式
当一个类需要克隆的时候,我们总不希望new一个对象,然后逐个属性去设置值。 这个时候,我们亟需一种
高效的对象copy方法,原型设计模式应运而生。
二、原型设计模式写法
原型设计模式实现:
public class Person implements Cloneable { private String userName; private String sex; private int age; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override protected Person clone() throws CloneNotSupportedException { Person person = (Person) super.clone(); return person; } @Override public String toString() { return "Person{" + "userName=‘" + userName + ‘\‘‘ + ", sex=‘" + sex + ‘\‘‘ + ", age=" + age + ‘}‘; }}
public static void main(String[] args) throws CloneNotSupportedException { Person p = new Person(); p.setAge(19); p.setUserName("小明"); p.setSex("男"); Person p1 = p.clone(); System.out.println(p.hashCode()); System.out.println(p1.hashCode()); p.setAge(12); System.out.println(p); System.out.println(p1);}执行结果
原型实现,在Person类中,实现了Cloneable 接口,然后重写clone方法,即可。
一切看似都很美好,然而,如果在Person中增加一个不是基本类型,也不是String类型的属性时,情况会令你意外。
1,浅拷贝
public class Person implements Cloneable { private String userName; private String sex; private int age; private Son son; public Son getSon() { return son; } public void setSon(Son son) { this.son = son; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override protected Person clone() throws CloneNotSupportedException { Person person = (Person) super.clone(); return person; } @Override public String toString() { return "Person{" + "userName=‘" + userName + ‘\‘‘ + ", sex=‘" + sex + ‘\‘‘ + ", age=" + age + ", son=" + son + ‘}‘; }}
public class Son { private String sonName; public String getSonName() { return sonName; } public void setSonName(String sonName) { this.sonName = sonName; } @Override public String toString() { return "Son{" + "sonName=‘" + sonName + ‘\‘‘ + ‘}‘; }}
public class Test { public static void main(String[] args) throws CloneNotSupportedException { Person p = new Person(); p.setAge(19); p.setUserName("小明"); p.setSex("男"); Son son = new Son(); son.setSonName("小明的孩子"); p.setSon(son); Person p1 = p.clone(); System.out.println(p.hashCode()); System.out.println(p1.hashCode()); p1.getSon().setSonName("隔壁老王的孩子"); p1.setAge(12); System.out.println(p); System.out.println(p1); }}运行结果如下
那么为什么能够出现这样的结果呢?
因为clone方法并不能穿透到son,也就是p和p1公用了son对象(p1对象对son的clone只是copy了指针,并没有完全copy,也就是浅拷贝),所以p和p1同时输出的“隔壁老王的孩子”。
如果我们希望实现完整的clone,该如何处理呢?我们需要深拷贝。
2,深拷贝
1)套娃式深拷贝
我们在浅拷贝的基础上修改,修改部分笔者用红色标识。
public class Person implements Cloneable { private String userName; private String sex; private int age; private Son son; public Son getSon() { return son; } public void setSon(Son son) { this.son = son; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override protected Person clone() throws CloneNotSupportedException { Person person = (Person) super.clone(); person.setSon(person.getSon().clone()); return person; } @Override public String toString() { return "Person{" + "userName=‘" + userName + ‘\‘‘ + ", sex=‘" + sex + ‘\‘‘ + ", age=" + age + ", son=" + son + ‘}‘; }}
public class Son implements Cloneable { private String sonName; public String getSonName() { return sonName; } public void setSonName(String sonName) { this.sonName = sonName; } @Override public String toString() { return "Son{" + "sonName=‘" + sonName + ‘\‘‘ + ‘}‘; } @Override protected Son clone() throws CloneNotSupportedException { return (Son) super.clone(); }}我们再来看结果:
很显然,得到了我们期望的结果,像不像套娃?
2)序列化深拷贝
首先改造Person
public class Person implements Serializable { private String userName; private String sex; private int age; private Son son; public Son getSon() { return son; } public void setSon(Son son) { this.son = son; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person{" + "userName=‘" + userName + ‘\‘‘ + ", sex=‘" + sex + ‘\‘‘ + ", age=" + age + ", son=" + son + ‘}‘; }}接着,改造Son
public class Son implements Serializable { private String sonName; public String getSonName() { return sonName; } public void setSonName(String sonName) { this.sonName = sonName; } @Override public String toString() { return "Son{" + "sonName=‘" + sonName + ‘\‘‘ + ‘}‘; } }Main方法
public class Test { public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException { Person p = new Person(); p.setAge(19); p.setUserName("小明"); p.setSex("男"); Son son = new Son(); son.setSonName("小明的孩子"); p.setSon(son); ByteArrayOutputStream bos=new ByteArrayOutputStream(); ObjectOutputStream oos=new ObjectOutputStream(bos); oos.writeObject(p); ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois=new ObjectInputStream(bis); Person p1= (Person) ois.readObject(); System.out.println(p.hashCode()); System.out.println(p1.hashCode()); p1.getSon().setSonName("隔壁老王的孩子"); p1.setAge(12); System.out.println(p); System.out.println(p1); }}来看看输出结果:
很显然,得到了我们期望的结果。
当然,可以把序列化过程封装到Person中。没有了套娃,又可以欢乐玩耍了。
总结:每一种拷贝都有自己的应用场景,要看具体的业务场景。
原文地址:https://www.cnblogs.com/x-j-p/p/12381088.html
时间: 2024-10-15 19:38:03