深度講解23種設計模式,力爭每種設計模式都刨析到底。廢話很少說,開始第二種設計模式 - 原型。設計模式
1、爲何有原型模式ide
當一個類須要克隆的時候,咱們總不但願new一個對象,而後逐個屬性去設置值。 這個時候,咱們亟需一種this
高效的對象copy方法,原型設計模式應運而生。spa
2、原型設計模式寫法設計
原型設計模式實現:指針
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類型的屬性時,狀況會令你意外。blog
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);
}
}
運行結果以下
那麼爲何可以出現這樣的結果呢?get
由於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中。沒有了套娃,又能夠歡樂玩耍了。
總結:每一種拷貝都有本身的應用場景,要看具體的業務場景。