詳解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;
復制對象:
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類中可能還存在別的對象引用。