1. 程式人生 > >Java中clone()方法的使用

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判斷),再為新物件騰出足夠多的記憶體,並通過“按位複製”將所有二進位制位從原來的物件複製到新物件的儲存空間。