詳解Java中的clone方法


詳解Java中的clone方法
#

參考:http://blog.csdn.net/zhangjg_blog/article/details/18369201/
  所謂的復制對象,首先要分配一個和源對象同樣大小的空間,在這個空間中創建一個新的對象。那么在java語言中,下面兩種方式創建對象有什么區別呢?

  1. 使用new操作符創建一個對象
  2. 使用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類中可能還存在別的對象引用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM