假设现在有个需求:一个对象A,在某一时刻A中已包含了一些有效值,此时可能需要一个和A完全相同对象B,并且此后对B的任何改动不会影响到A的值,也就算是说,A与B是两个相对独立的对象,但B的初始值是有A对象确定的。考虑下赋值语句是否可以达到此效果?
在Java中赋值语句是达不到此效果的。
Person person1 = new Person("Jim", "123456");
Person person2 = person1;

从图中可以看出用赋值语句,两个对象实际指向的是同一个引用,指向的是同一块地址空间。
其实我们可以使用clone()来达到上述目的。
public class CloneClass implements Cloneable {
private int id;
@Override
protected Object clone() throws CloneNotSupportedException {
CloneClass o = null;
try {
o = (CloneClass) super.clone();
} catch (Exception e) {
e.printStackTrace();
}
return o;
}
}
实现clone()的步骤
1.期望实现clone()的Class实现了Cloneable Interface.
2.重载了clone()方法。在clone()中调用super的clone().无论需实现clone()的Class继承结构是什么样的。super.clone()都直接或间接调用了java.lang.Object类的clone().
至于为什么不直接new一个对象,因为Object类的clone()是一个native方法,native方法的效率远高于Java的非native方法。
Shadow Clone(影子Clone)
Shadow clone 并不是对对象的完整clone,换句话说clone后两个对象A和B还会中的某些对象指向的对象是同一个。如下面ShadowTest的实例test1和test2中的mArrayList指向的是同一个对象。
public class ShadowTest implements Cloneable {
private int mId;
private ArrayList mArrayList = new ArrayList();
public void setId(int id) {
mId = id;
}
public void add(int x) {
mArrayList.add(x);
}
@Override
public String toString() {
return String.valueOf(mId) + ";" + mArrayList.toString();
}
@Override
protected Object clone() {
ShadowTest test = null;
try {
test = (ShadowTest) super.clone();
} catch (Exception e) {
e.printStackTrace();
}
return test;
}
}
public class ShadowClone {
public static void main(String[] args) {
ShadowTest test1 = new ShadowTest();
test1.setId(5);
test1.add(30);
System.out.println("test1 = " + test1.toString());
ShadowTest test2 = (ShadowTest) test1.clone();
System.out.println("test2 = " + test2.toString());
test2.setId(3);
System.out.println("test1 = " + test1.toString());
System.out.println("test2 = " + test2.toString());
test2.add(31);
System.out.println("test1 = " + test1.toString());
System.out.println("test2 = " + test2.toString());
}
}
运行结果:
test1 = 5;[30]
test2 = 5;[30]
test1 = 5;[30]
test2 = 3;[30]
test1 = 5;[30, 31]
test2 = 3;[30, 31]
Deep Clone
与Shadow Clone不同,Deep Clone是对对象的完整clone。
public class DeepTest implements Cloneable {
private int mId;
private ArrayList mArrayList = new ArrayList();
public void setId(int id) {
mId = id;
}
public void add(int x) {
mArrayList.add(x);
}
@Override
public String toString() {
return String.valueOf(mId) + ";" + mArrayList.toString();
}
@Override
public Object clone() {
DeepTest test = null;
try {
test = (DeepTest) super.clone();
test.mArrayList = (ArrayList) mArrayList.clone();
} catch (Exception e) {
e.printStackTrace();
}
return test;
}
}
public class DeepClone {
public static void main(String[] args) {
DeepTest test1 = new DeepTest();
test1.setId(5);
test1.add(30);
System.out.println("test1 = " + test1.toString());
DeepTest test2 = (DeepTest) test1.clone();
System.out.println("test2 = " + test2.toString());
test2.setId(3);
System.out.println("test1 = " + test1.toString());
System.out.println("test2 = " + test2.toString());
test2.add(31);
System.out.println("test1 = " + test1.toString());
System.out.println("test2 = " + test2.toString());
}
}
运行结果:
test1 = 5;[30]
test2 = 3;[30]
test1 = 5;[30]
test2 = 3;[30, 31]
从上面例子来看,其实Object类的clone()只是对对象地址空间的简单复制,对于类中的复杂对象及数据结构不很好的复制,需要实现者调用复杂对象或者数据结构的clone()来达到Deep Clone。
另外为了避免误用,可以增添如deepCopy()的函数来实现Deep Clone.