clone()方法是Object的native方法。protected native Object clone() throws CloneNotSupportedException; 声明为protected,表明子类必须重新实现该方法,除非是与Obeject类在一个包里,后者是不可能的。而实际上,作为native方法clone()已经有一份field to field的浅拷贝实现,实际上是不需要一定重写的。这种情况下,需要的做法就是覆写clone()方法,在方法里通过super.clone()调用Object的clone()。
而Cloneable是标记型接口,实现了Cloneable才可以实现clone()方法。否则使用clone()方法会报错。
下面是ArrayList的clone()
/** * Returns a shallow copy of this <tt>ArrayList</tt> instance. (The * elements themselves are not copied.) * * @return a clone of this <tt>ArrayList</tt> instance */ public Object clone() { try { ArrayList<?> v = (ArrayList<?>) super.clone(); v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(e); } }
这里为何不是简单的super.clone()浅拷贝呢?因为成员变量是复杂类型时(涉及成员变量为对象的引用),就需要深拷贝。
下面做个小实验,先使用浅拷贝,验证普通的成员变量是ok的:
package a; public class CloneTest implements Cloneable { private int v_a; public void setV_a(int v) { v_a = v; } public Object clone() throws CloneNotSupportedException { return super.clone(); } public void print_v_a() { System.out.println(v_a); } public static void main(String[] args) throws CloneNotSupportedException { CloneTest ct0 = new CloneTest(); ct0.setV_a(66); CloneTest ct1 = (CloneTest)ct0.clone(); ct1.print_v_a(); ct0.setV_a(88); ct1.print_v_a(); ct0.print_v_a(); } }
先设置ct0的v_a对象为66,然后ct1对象是ct0的拷贝,打印ct1的v_a,也为66,说明拷贝成功。 之后重新设置ct0的值为88,ct1的值没变还是66。
package a; import java.util.Arrays; class A { private int v; public void setV(int v) { this.v = v; } public void p_v() { System.out.println(v); } } public class CloneTest implements Cloneable { private A v_a; public void setV_a(A v) { v_a = v; } public Object clone() throws CloneNotSupportedException { return super.clone(); } public void print_v_a() { v_a.p_v(); } public static void main(String[] args) throws CloneNotSupportedException { CloneTest ct0 = new CloneTest(); A a = new A(); a.setV(66); ct0.setV_a(a); CloneTest ct1 = (CloneTest)ct0.clone(); ct1.print_v_a(); a.setV(88); ct0.setV_a(a); ct1.print_v_a(); } }
上面这个例子就体现出了浅拷贝的弱点,输出为66 88。
ct1是浅拷贝的ct0,此时ct0的v_a(成员变量,A对象)的v值为66。拷贝后,ct1的v_a(A对象的v)输出也是66。然后重设ct0的v_a(A对象的v)为88,再输出ct1的v_a(A对象的v),竟然也是88。说明二者的引用指向的是同样的堆内存。
浅拷贝情况下,两个对象的成员变量(A对象)引用的是同一个堆内存,并没有完全实现拷贝后内存独立。
这种情况就需要深拷贝。
例如文章最开始提到的ArrayList的clone()的写法。