先做個標記
http://www.iteye.com/topic/182772
http://www.blogjava.net/jerry-zhaoj/archive/2009/10/14/298141.html
關於super.clone的理解
http://hi.baidu.com/%BB%AA%CF%C4%D1%A7%C9%FA%C1%AA%C3%CB/blog/item/7d70a43842622832b8998f86.html
http://tieba.baidu.com/p/938267457
http://topic.csdn.net/u/20080326/09/a48470f3-f2c2-43c4-af56-fa8ffc12b629.html
http://www.iteye.com/topic/1113790
如何查看JDK源碼
http://hi.baidu.com/koflance/blog/item/07809915d6f70e5cf3de32dd.html
http://www.iteye.com/topic/1113790
java對象的克隆步驟:
1.類需要實現Cloneable接口
2 覆蓋clone方法,調用super.clone即可。如果是複合類型,如數組,集合類,還需要繼續clon下去。
類A1只含有原生類型的屬性,A2、A3類含有複合類型的屬性,實現起來要clone到底,不然只會拷貝一個引用,從而實現淺拷貝(影子拷貝),實際上只有一個堆對象。兩個引用實際上指向了一個對象。
A1的實現
public class A1 implements Cloneable {
public int age;
public Object clone() {
A1 o = null;
try {
o = (A1) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
Object o = new Object();
}
A2的實現:
public class A2 implements Cloneable {
public String[] name;
public Object clone() {
A2 o = null;
try {
o = (A2) super.clone();
o.name = (String[]) name.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
public A2() {
name = new String[2];
}
}
A3是最複雜的
package com.tmall;
import java.util.Vector;
public class A3 implements Cloneable {
public String name[];
public Vector<B> claB;
public A3() {
name = new String[2];
claB = new Vector<B>();
}
public Object clone() {
A3 o = null;
try {
o = (A3) super.clone();
o.name = (String[]) name.clone();// 深度clone
o.claB = new Vector<B>();// 將clone進行到底
for (int i = 0; i < claB.size(); i++) {
B temp = (B) claB.get(i).clone();// 當然Class B也要實現相應clone方法
o.claB.add(temp);
}
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
其中B類的定義:
public class B {
public int age;
public Object clone() {
B o = null;
try {
o = (B) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return o;
}
}
兩個測試方法:
public static void testA1(){
A1 a11 = new A1();
A1 a12 = (A1)a11.clone();
a11.age = 10;
a12.age = 20;
System.out.println(a11.age);
System.out.println(a12.age);
}
public static void testA2(){
A2 a1=new A2();
a1.name[0]="a";
a1.name[1]="1";
A2 a2=(A2)a1.clone();
a2.name[0]="b";
a2.name[1]="1";
System.out.println("a1.name="+a1.name);
System.out.println("a1.name="+a1.name[0]+a1.name[1]);
System.out.println("a2.name="+a2.name);
System.out.println("a2.name="+a2.name[0]+a2.name[1]);
}
運行結果,可以知道成功實現了深拷貝。
進一步研究:
1 . 翻閱cloneable接口的源碼,發現是一個空接口,啥都沒有。
package java.lang;
/**
* A class implements the <code>Cloneable</code> interface to
* indicate to the {@link java.lang.Object#clone()} method that it
* is legal for that method to make a
* field-for-field copy of instances of that class.
* <p>
* Invoking Object's clone method on an instance that does not implement the
* <code>Cloneable</code> interface results in the exception
* <code>CloneNotSupportedException</code> being thrown.
* <p>
* By convention, classes that implement this interface should override
* <tt>Object.clone</tt> (which is protected) with a public method.
* See {@link java.lang.Object#clone()} for details on overriding this
* method.
* <p>
* Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
* Therefore, it is not possible to clone an object merely by virtue of the
* fact that it implements this interface. Even if the clone method is invoked
* reflectively, there is no guarantee that it will succeed.
*
* @author unascribed
* @version 1.17, 11/17/05
* @see java.lang.CloneNotSupportedException
* @see java.lang.Object#clone()
* @since JDK1.0
*/
public interface Cloneable {
}
在這篇帖子中對這個問題就行了討論
2.
clone方法的錯誤使用。
在不止一篇帖子裏面,錯誤地使用了clone這個方法。
作者是這樣調用clone方法的:
A a1=new A();
A a2=new A(); **
a2=(A)a1.clone();
其實做一次實驗就可以知道,**行是多餘的。 A1 a11 = new A1();
A1 a12 = (A1) a11.clone();
A1 a13 = new A1();
System.out.println("a11的地址是" + a11);
System.out.println("a12的地址是" + a12);
System.out.println("a13的地址是" + a13);
a13 = (A1) a11.clone();
System.out.println("a13的地址是" + a13);
我的電腦運行結果是
a11的地址是com.tmall.A1@c17164
a12的地址是com.tmall.A1@1fb8ee3
a13的地址是com.tmall.A1@61de33
a13的地址是com.tmall.A1@14318bb
說明a12克隆成功;
A1 a12 = (A1) a11.clone();
是沒有問題的。
反而實現new 一個對象如a13,在調用clone()方法會多此一舉:
A1 a13 = new A1();
a13 = (A1) a11.clone();
可以看到運行結果裏面,a13的地址換了兩次。第一次是new出來的新對象,第二次是克隆出來的新對象,兩次地址都不等於那個被clone的對象a11。
我翻閱了《effectice java》的條款11,“謹慎地覆蓋clone”。作者Joshua Bloch(可是google的首席java工程師)第三段寫道:
“如果實現cloneable接口是對某個類起到作用,類和它的所有超類都必須遵守一個想當複雜的、不可實施的,並且基本上沒有文檔說明的協議。由此得到一種語言之外的機制:
無需要調用構造器就可以創建對象”,紅色部分也說明了**行new 一個類是多餘的。
3. Object類裏面的clone定義。
翻看JDK源碼,Object類裏面的clone方法定義如下
protected native Object clone() throws CloneNotSupportedException;
使用C/C++來實現的。
翻了翻相關資料,java clone 克隆 super.clone
是“bitwise(逐位)的複製, 將該對象的內存空間完全複製到新的空間中去”這樣實現的。
另外這個方法是protected的,不同的包是不能用的。這就可以解釋爲什麼我們不能顯示地調用Object.clone()這個方法。因爲Object這個類是放在java,lang這個包裏面的,而clone()方法是protected的,是不可見的。如果這樣寫
Object o1 = new Object();
Object o2 = o1.clone();
編譯器肯定會報錯的:
之前我不理解A類中爲什麼用super.clone()這樣子的寫法,現在明白了。
4. 如果一個類實現了Cloneable接口,Object的clone方法就會返回該對象的逐域拷貝,否則就會拋出CloneNotSupportedException異常。
來自《effective java》條款11的第二段話。所以要實現對象的clone,必須實現cloneable接口。