詳解Java中的clone方法#
參考:http://blog.csdn.net/zhangjg_blog/article/details/18369201/
所謂的複制對象,首先要配置設定一個和源對象同樣大小的空間,在這個空間中建立一個新的對象。那麼在java語言中,下面兩種方式建立對象有什麼差別呢?
- 使用new操作符建立一個對象
- 使用clone方法複制一個對象
那麼這兩種方式有什麼相同和不同呢? new操作符的本意是配置設定記憶體。程式執行到new操作符時, 首先去看new操作符後面的類型,因為知道了類型,才能知道要配置設定多大的記憶體空間。配置設定完記憶體之後,再調用構造函數,填充對象的各個域,這一步叫做對象的初始化,構造方法傳回後,一個對象建立完畢,可以把他的引用(位址)釋出到外部,在外部就可以使用這個引用操縱這個對象(當然,由于指令的重排序,釋出對象可能在構造函數傳回之前,詳細看 http://www.cnblogs.com/xzwblog/p/7225946.html#_label0_3)。而clone在第一步是和new相似的, 都是配置設定記憶體,調用clone方法時,配置設定的記憶體和源對象(即調用clone方法的對象)相同,然後再使用源對象中對應的各個域,填充新對象的域, 填充完成之後,clone方法傳回,一個新的相同的對象被建立,同樣可以把這個新對象的引用釋出到外部。
複制引用or複制對象
複制引用:下面p和p1隻是引用而已,他們都指向了一個相同的對象Person(23, "zhang") 。 可以把這種現象叫做引用的複制。
Person p = new Person(23, "zhang");
Person p1 = p;
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuATOzMTO0ADN20SO0kjMyAzM5EDNycDM3EDMy0SN2UjN1ETMvw1NwcTMwIzLcVjN1YTNxEzLcd2bsJ2Lc12bj5ycn9Gbi52YuUTMwIzcldWYtl2Lc9CX6MHc0RHaiojIsJye.png)
複制對象:
Person p = new Person(23, "zhang");
Person p1 = (Person) p.clone();
淺複制or深複制
淺複制
被複制對象的所有變量都含有與原來的對象相同的值,而所有的對其他對象的引用仍然指向原來的對象。換言之,淺複制僅僅複制所考慮的對象,而不複制它所引用的對象。
深複制
被複制對象的所有變量都含有與原來的對象相同的值,除去那些引用其他對象的變量。那些引用其他對象的變量将指向被複制過的新對象,而不再是原有的那些被引用的對象。換言之,深複制把要複制的對象所引用的對象都複制了一遍。
Java的clone()方法
⑴clone方法将對象複制了一份并傳回給調用者。一般而言,clone()方法滿足:
①對任何的對象x,都有x.clone() !=x//克隆對象與原對象不是同一個對象
②對任何的對象x,都有x.clone().getClass()= =x.getClass()//克隆對象與原對象的類型一樣
③如果對象x的equals()方法定義恰當,那麼x.clone().equals(x)應該成立。
⑵Java中對象的克隆
①為了擷取對象的一份拷貝,我們可以利用Object類的clone()方法。
②在派生類中覆寫基類的clone()方法,并聲明為public。
③在派生類的clone()方法中,調用super.clone()。
④在派生類中實作Cloneable接口。
繼承自java.lang.Object類的clone()方法是淺複制, 在編寫程式時要注意這個細節。
覆寫Object中的clone方法, 實作深複制
現在為了要在clone對象時進行深複制, 那麼就要Clonable接口,覆寫并實作clone方法,除了調用父類中的clone方法得到新的對象, 還要将該類中的引用變量也clone出來。
public class Test {
static class Body implements Cloneable {
public Head head;
public Body() {
}
public Body(Head head) {
this.head = head;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Body newBody = (Body) super.clone();
newBody.head = (Head) head.clone();
return newBody;
}
}
static class Head implements Cloneable {
public Face face;
public Head() {
}
public Head(Face face) {
this.face = face;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
static class Face implements Cloneable {
public Face() {
}
}
public static void main(String[] args) throws CloneNotSupportedException {
Body body = new Body(new Head());
Body body1 = (Body) body.clone();
System.out.println("body == body1 : " + (body == body1));
System.out.println("body.head == body1.head : " + (body.head == body1.head));
}
}
列印結果為:
body == body1 : false
body.head == body1.head : false
由此可見, body和body1内的head引用指向了不同的Head對象, 也就是說在clone Body對象的同時, 也複制了它所引用的Head對象, 進行了深複制。但實際上上面代碼還不是真正意義上的深複制,可以說是不徹底的深複制。因為在拷貝Head類時,預設執行的是淺複制,也就是說Head中組合的Face對象并不會被複制。記憶體結構圖如下圖所示:
實作完全的深複制是很難的,因為Face類中可能還存在别的對象引用。
作者:何必等明天
出處:http://www.cnblogs.com/xzwblog/
歡迎轉載,但未經作者同意必須保留此段聲明,否則保留追究法律責任的權利.