天天看點

詳解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;  
           
詳解Java中的clone方法

  複制對象:

Person p = new Person(23, "zhang");  
Person p1 = (Person) p.clone();  
           
詳解Java中的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對象并不會被複制。記憶體結構圖如下圖所示:

詳解Java中的clone方法

  實作完全的深複制是很難的,因為Face類中可能還存在别的對象引用。

作者:何必等明天

出處:http://www.cnblogs.com/xzwblog/

歡迎轉載,但未經作者同意必須保留此段聲明,否則保留追究法律責任的權利.