原型模式: 原型模式又叫克隆模式 Java自帶克隆模式 實現克隆模式必須實現Cloneable 介面,如果不實現會發生java.lang.CloneNotSupportedException異常 當某個類的屬性已經設定好需要創建很多相同屬性值的對象的時候使用clone模式非常方便 使用clone模式 ...
原型模式:
- 原型模式又叫克隆模式
- Java自帶克隆模式
- 實現克隆模式必須實現Cloneable
- 介面,如果不實現會發生java.lang.CloneNotSupportedException異常
- 當某個類的屬性已經設定好需要創建很多相同屬性值的對象的時候使用clone模式非常方便
- 使用clone模式不見得比傳統的new方式性能高
- 淺克隆和深克隆
先看下麵的代碼,沒有實現Cloneable介面
package com.srr.dp.clone; /** * (原型模式)克隆模式 */ public class Appler /*implements Cloneable*/{ private String clor; private int weight; private int volume; private StringBuilder descr; public Appler(String clor) { this.clor = clor; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Appler{" + "clor='" + clor + '\'' + ", weight=" + weight + ", volume=" + volume + ", descr=" + descr + '}'; } } package com.srr.dp.clone; public class T { public static void main(String[] args) throws CloneNotSupportedException { Appler appler = new Appler("yellow"); Appler appler1 = (Appler) appler.clone(); System.out.println(appler1); } }
運行結果:
淺拷貝:
package com.srr.dp.clone; /** * (原型模式)克隆模式 * 淺拷貝 */ public class Appler implements Cloneable { private String clor; private int weight; private int volume; private Location loc; public Appler(String clor,int weight,int volume,Location loc) { this.clor = clor; this.weight = weight; this.volume = volume; this.loc = loc; } public String getClor() { return clor; } public void setClor(String clor) { this.clor = clor; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } public int getVolume() { return volume; } public void setVolume(int volume) { this.volume = volume; } public Location getLoc() { return loc; } public void setLoc(Location loc) { this.loc = loc; } @Override protected Object clone() throws CloneNotSupportedException { //loc = (Locaton) loc.clone(); return super.clone(); } @Override public String toString() { return "Appler{" + "clor='" + clor + '\'' + ", weight=" + weight + ", volume=" + volume + ", loc=" + loc + '}'; } } package com.srr.dp.clone; public class Location { String name; public Location(String name){ this.name = name; } @Override public String toString() { return "Locaton{" + "name='" + name + '\'' + '}'; } } package com.srr.dp.clone; /** * 測試代碼 */ public class T { public static void main(String[] args) throws CloneNotSupportedException { Appler appler = new Appler("yellow",1,1,new Location("洛川")); Appler appler1 = (Appler) appler.clone(); appler.setClor("red"); appler.getLoc().name = "寶雞"; System.out.println("appler1 = "+appler1); System.out.println("appler = "+appler); } }
運行結果:
從結果發現,當改變appler 的顏色還有location的值後,拷貝的apper1對象的顏色未發生改變但是location發生了改變。
這就是淺拷貝,引用對象無法保證拷貝之後完全獨立只是拷貝了地址但是地址指向的對象是共用的,
雖然String類型也是引用類型但是共用常量池所以不會有這個問題。
那麼如何讓引用類型拷貝之後獨立呢?
那麼就要使用深拷貝請看如下代碼:
package com.srr.dp.clone; /** * (原型模式)克隆模式 * 淺拷貝 */ public class Appler implements Cloneable { private String clor; private int weight; private int volume; private Location loc; public Appler(String clor,int weight,int volume,Location loc) { this.clor = clor; this.weight = weight; this.volume = volume; this.loc = loc; } public String getClor() { return clor; } public void setClor(String clor) { this.clor = clor; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } public int getVolume() { return volume; } public void setVolume(int volume) { this.volume = volume; } public Location getLoc() { return loc; } public void setLoc(Location loc) { this.loc = loc; } @Override protected Object clone() throws CloneNotSupportedException { Appler appler = (Appler)super.clone(); appler.loc = (Location) loc.clone();; return appler; } @Override public String toString() { return "Appler{" + "clor='" + clor + '\'' + ", weight=" + weight + ", volume=" + volume + ", loc=" + loc + '}'; } } package com.srr.dp.clone; public class Location implements Cloneable{ String name; public Location(String name){ this.name = name; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Locaton{" + "name='" + name + '\'' + '}'; } } package com.srr.dp.clone; /** * 測試代碼 */ public class T { public static void main(String[] args) throws CloneNotSupportedException { Appler appler = new Appler("yellow",1,1,new Location("洛川")); Appler appler1 = (Appler) appler.clone(); appler.setClor("red"); appler.getLoc().name = "寶雞"; System.out.println("appler1 = "+appler1); System.out.println("appler = "+appler); } }
運行結果:
從結果發現,當改變appler 的顏色還有location的值後,拷貝的apper1對象的顏色未發生改變location也發生了改變。
上面說到String類型的拷貝不存在淺拷貝的問題,那麼StringBuilder或者StringBuffer呢,鑒於篇幅這裡使用StringBuilder來舉例
請看代碼:
package com.srr.dp.clone; /** * (原型模式)克隆模式 * 淺拷貝 */ public class Appler implements Cloneable { private String color; private int weight; private int volume; private Location loc; public String getColor() { return color; } public StringBuilder getDesc() { return desc; } public void setDesc(StringBuilder desc) { this.desc = desc; } private StringBuilder desc = new StringBuilder("好吃"); public Appler(String color,int weight,int volume,Location loc) { this.color = color; this.weight = weight; this.volume = volume; this.loc = loc; } public String getClor() { return color; } public void setColor(String color) { this.color = color; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } public int getVolume() { return volume; } public void setVolume(int volume) { this.volume = volume; } public Location getLoc() { return loc; } public void setLoc(Location loc) { this.loc = loc; } @Override protected Object clone() throws CloneNotSupportedException { Appler appler = (Appler)super.clone(); appler.loc = (Location) loc.clone(); return appler; } @Override public String toString() { return "Appler{" + "color='" + color + '\'' + ", weight=" + weight + ", volume=" + volume + ", loc=" + loc + ", desc=" + desc + '}'; } } package com.srr.dp.clone; public class Location implements Cloneable{ String name; public Location(String name){ this.name = name; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Locaton{" + "name='" + name + '\'' + '}'; } } package com.srr.dp.clone; /** * 測試代碼 */ public class T { public static void main(String[] args) throws CloneNotSupportedException { Appler appler = new Appler("yellow",1,1,new Location("洛川")); Appler appler1 = (Appler) appler.clone(); appler.getDesc().append("得不得了"); appler.getLoc().name = "寶雞"; System.out.println("appler1 = "+appler1); System.out.println("appler = "+appler); } }
運行結果:
這是是後你會發現當appler的desc值發生改變之後,apper1的值也發生改變了,說明StringBuilder的拷貝方式為淺拷貝,那麼如何實現深拷貝呢
請看代碼:
package com.srr.dp.clone; /** * (原型模式)克隆模式 * 淺拷貝 */ public class Appler implements Cloneable { private String color; private int weight; private int volume; private Location loc; public String getColor() { return color; } public StringBuilder getDesc() { return desc; } public void setDesc(StringBuilder desc) { this.desc = desc; } private StringBuilder desc = new StringBuilder("好吃"); public Appler(String color,int weight,int volume,Location loc) { this.color = color; this.weight = weight; this.volume = volume; this.loc = loc; } public String getClor() { return color; } public void setColor(String color) { this.color = color; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } public int getVolume() { return volume; } public void setVolume(int volume) { this.volume = volume; } public Location getLoc() { return loc; } public void setLoc(Location loc) { this.loc = loc; } @Override protected Object clone() throws CloneNotSupportedException { Appler appler = (Appler)super.clone(); appler.loc = (Location) loc.clone(); appler.desc = new StringBuilder(this.desc); return appler; } @Override public String toString() { return "Appler{" + "color='" + color + '\'' + ", weight=" + weight + ", volume=" + volume + ", loc=" + loc + ", desc=" + desc + '}'; } } package com.srr.dp.clone; public class Location implements Cloneable{ String name; public Location(String name){ this.name = name; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } @Override public String toString() { return "Locaton{" + "name='" + name + '\'' + '}'; } } package com.srr.dp.clone; /** * 測試代碼 */ public class T { public static void main(String[] args) throws CloneNotSupportedException { Appler appler = new Appler("yellow",1,1,new Location("洛川")); Appler appler1 = (Appler) appler.clone(); appler.getDesc().append("得不得了"); appler.getLoc().name = "寶雞"; System.out.println("appler1 = "+appler1); System.out.println("appler = "+appler); } }
運行結果:
這是是後你會發現當appler的desc值發生改變之後,apper1的值並沒有發生改變。
寫到這裡原型模式就介紹完了。
原創不易,請多多支持!