简单对象的拷贝,直接使用其clone方法 即可, 不会有什么问题:
class Dog implements Cloneable public Dog clone() { int age; String name; // getter setter Dog myDog = null; try { myDog = (Dog) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return myDog; }
// any test ...
如此简单!
不过,如果对象有嵌套,我们还是使用这个做法(浅拷贝), 不注意就会出问题:
package design.creator.prototype; import java.util.ArrayList; import java.util.List; /** * 浅拷贝: */ class Dog implements Cloneable { int age; String name; List list; Pojo pojo; public Dog(String tempName) { name = tempName; list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); pojo = new Pojo(); pojo.setV1(111); pojo.setV2("aa"); } // public void ShowName() { // System.out.println(name); // } public Dog clone() { Dog myDog = null; try { myDog = (Dog) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return myDog; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public List getList() { return list; } public void setList(List list) { this.list = list; } @Override public String toString() { return "Dog [age=" + age + ", name=" + name + ", list=" + list + "]" + ", pojo=" + pojo + "]"; } public Pojo getPojo() { return pojo; } public void setPojo(Pojo pojo) { pojo = pojo; } } class Pojo { int v1; String v2; public int getV1() { return v1; } public void setV1(int v1) { this.v1 = v1; } public String getV2() { return v2; } public void setV2(String v2) { this.v2 = v2; } @Override public String toString() { return "Pojo [v1=" + v1 + ", v2=" + v2 + "]"; } } public class PrototypeTest { public static void main(String[] args) { Dog myDog = new Dog("热狗"); myDog.setAge(12); Dog newDog = (Dog) myDog.clone(); System.out.println(" myDog " + myDog ); System.out.println(" newDog " + newDog ); // myDog.ShowName(); // newDog.ShowName(); myDog.setName("aaaaa"); myDog.setAge(33); myDog.getList().clear(); myDog.getPojo().setV1(222); myDog.getPojo().setV2("bbb"); // myDog.ShowName(); // newDog.ShowName(); System.out.println(" myDog " + myDog ); System.out.println(" newDog " + newDog ); } }
打印
myDog Dog [age=12, name=热狗, list=[1, 2, 3]], pojo=Pojo [v1=111, v2=aa]] newDog Dog [age=12, name=热狗, list=[1, 2, 3]], pojo=Pojo [v1=111, v2=aa]] myDog Dog [age=33, name=aaaaa, list=[]], pojo=Pojo [v1=222, v2=bbb]] newDog Dog [age=12, name=热狗, list=[]], pojo=Pojo [v1=222, v2=bbb]]
你可能不懂为什么newDog 的name没变化,而newDog 的pojo、list都发生了变化—— 原来java 的clone 方法把 String当做了普通字段并进行了深复制, 而其他对象类型数据仍然的浅复制。
那么正确的做法是:
package design.creator.prototype; import java.util.ArrayList; import java.util.List; /** * 深度拷贝: */ class Dog implements Cloneable { int age; String name; List list; Pojo pojo; public Dog(String tempName) { name = tempName; list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); pojo = new Pojo(); pojo.setV1(111); pojo.setV2("aa"); } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public List getList() { return list; } public void setList(List list) { this.list = list; } @Override public String toString() { return "Dog [age=" + age + ", name=" + name + ", list=" + list + "]" + ", pojo=" + pojo + "]"; } public Pojo getPojo() { return pojo; } public void setPojo(Pojo pojo) { pojo = pojo; } public Dog clone() { Dog myDog = null; try { myDog = (Dog) super.clone(); myDog.list = (List) ((ArrayList)myDog.list).clone(); // 想要调用其clone方法,必须1 implements Cloneable 2 对其重写clone myDog.pojo = (Pojo) myDog.pojo.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return myDog; } } class Pojo implements Cloneable{ int v1; String v2; public int getV1() { return v1; } public void setV1(int v1) { this.v1 = v1; } public String getV2() { return v2; } public void setV2(String v2) { this.v2 = v2; } @Override public String toString() { return "Pojo [v1=" + v1 + ", v2=" + v2 + "]"; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } public class PrototypeTest { public static void main(String[] args) { Dog myDog = new Dog("热狗"); myDog.setAge(12); Dog newDog = (Dog) myDog.clone(); System.out.println(" myDog " + myDog ); System.out.println(" newDog " + newDog ); // myDog.ShowName(); // newDog.ShowName(); myDog.setName("aaaaa"); myDog.setAge(33); myDog.getList().clear(); myDog.getPojo().setV1(222); myDog.getPojo().setV2("bbb"); // myDog.ShowName(); // newDog.ShowName(); System.out.println(" myDog " + myDog ); System.out.println(" newDog " + newDog ); } }
总结:
clone 方法只是浅拷贝,也就是说他只对象的第一层属性进行拷贝,其对象中的对象是不会进行重新拷贝的, 而仅仅只是拷贝那个引用。 如果对象有嵌套,那么需要注意重写相关步骤,使用 深拷贝。
参考:
http://blog.csdn.net/jariwsz/article/details/8588570
http://blog.csdn.net/xiaofengcanyuexj/article/details/23212189