Java中clone()方法的使用
Java程式設計思想
物件克隆是指建立已有物件的一個拷貝,如果想要修改一個物件,但同時不想改變呼叫者的物件,那麼克隆會是很好的解決方式。
在Java中,實現物件的克隆只需要覆蓋Object提供的clone()方法,並將方法訪問級別改為public
,同時要注意物件所屬類必須實現Cloneable
介面,否則在呼叫clone()方法時會丟擲CloneNotSupportedException
異常。
1 clone()方法的使用
class Test implements Cloneable{ public int ii; public String ss; public Test2 test2; public Test() { super(); } public String format() { return String.format("ii = %s, ss = %s, test2 = %s", ii, ss, test2); } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } } class Test2 implements Cloneable{ public int ii2; @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } } public class CloneTest { public static void main(String[] args) throws Exception { Test t = new Test(); t.ii = 1; t.ss = "1"; t.test2 = new Test2(); Test t2 = (Test) t.clone(); System.out.println(t); System.out.println(t2); System.out.println(t.format()); System.out.println(t2.format()); t2.ii = 2; t2.ss = "2"; System.out.println(t.format()); System.out.println(t2.format()); } }
輸出:
[email protected]
[email protected]
ii = 1, ss = 1, test2 = [email protected]
ii = 1, ss = 1, test2 = [email protected]
ii = 1, ss = 1, test2 = [email protected]
ii = 2, ss = 2, test2 = [email protected]
可以看到,通過覆蓋clone()方法,在clone()方法中通過super.clone()
的呼叫,我們可以獲得物件的拷貝,兩個物件引用指向不同的記憶體區域,同時擁有了相同的屬性值。當我們對拷貝物件作出修改時,並不會影響原有的物件。
2 淺拷貝和深拷貝
從上面的例子我們可以看到,clone()方法的使用的確返回物件的一個拷貝,但如果物件中的屬性是另一個引用型別的話,那麼clone()方法的簡單呼叫並不會把該引用指向的物件再作一次拷貝,同時把新物件屬性裡的引用指向這個拷貝,而只是把引用(記憶體地址)作一次拷貝,結果是兩個屬性引用指向的仍然是同一個物件。這種只拷貝了原始資料型別的拷貝,我們就稱作淺拷貝
。(這裡我們可能發現了,String型別是引用型別,為什麼拷貝物件中String型別變數改變了,原有物件卻沒改變,其實主要是因為String的不可變性,拷貝物件改變的只是引用而引用指向的內容)
有淺拷貝
就有深拷貝
,深拷貝會拷貝所有的原始資料屬性,同時也拷貝引用屬性指向的動態分配的記憶體。那麼要如何實現深拷貝呢?
@Override
public Object clone() throws CloneNotSupportedException {
Test t = (Test)super.clone();
t.test2 = (Test2) test2.clone();
return t;
}
方法就是在覆蓋clone()方法時,對物件中引用變數也明確呼叫一次clone()方法進行一次克隆。
修改後輸出:
[email protected]
[email protected]
ii = 1, ss = 1, test2 = [email protected]
ii = 1, ss = 1, test2 = [email protected]
ii = 1, ss = 1, test2 = [email protected]
ii = 2, ss = 2, test2 = [email protected]
3 Object的clone()方法做了什麼
我們發現,在覆蓋clone()方法的時候,我們有一句super.clone()
是必有的,通過super.clone()方法傳遞呼叫,我們知道,最後一定會呼叫到Object的clone()方法,那麼,Object.clone()方法會做什麼呢?
Object.clone()會檢查原先的物件有多大(通過執行時型別資訊RTTI判斷),再為新物件騰出足夠多的記憶體,並通過“按位複製”將所有二進位制位從原來的物件複製到新物件的儲存空間。