简单对象的拷贝,直接使用其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