天天看點

java技巧——deep copy

我們都知道,在Java裡面如果想要clone一個對象,可以讓類實作Cloneable接口,然後調用其clone方法(最終調用Object的clone方法)。但是這個隻是淺拷貝,如果這個類的屬性都是私有類型或其包裝類,或者是immutable objects(比如String),那clone能夠工作很好。 但是一旦其包括mutable objects,比如StringBuffer或者别的對象的引用,那麼shallow copy就會導緻一個對象的修改會影響另外一個對象。

是以,在這種情況下,我們就需要自己來實作deep copy。最先想到的就是override clone方法,當然你需要在裡面周遊所有的mutable屬性然後依次clone它們。當然這還不是推薦的做法,在Effective Java "Item 11: Override clone judiciously"中就明确不推薦這種辦法,取而代之的是copy constructor or copy factory。

如果不想針對每個對象都寫一個自己的copy constructor or copy factory,可以有一些通用的方法,如果性能不是問題的話。

1、利用Java object serialization機制,代碼如下,唯一的限制是你的類必須實作Serializable接口,不是什麼過分的要求。

public class ObjectCloner {

	/**
	 * Returns a copy of the object, or null if the object cannot be serialized.
	 */
	public static Object copy(Object orig) {
		Object obj = null;
		try {
			// Write the object out to a byte array
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			ObjectOutputStream out = new ObjectOutputStream(bos);
			out.writeObject(orig);
			out.flush();
			out.close();

			// Make an input stream from the byte array and read
			// a copy of the object back in.
			ObjectInputStream in = new ObjectInputStream(
					new ByteArrayInputStream(bos.toByteArray()));
			obj = in.readObject();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException cnfe) {
			cnfe.printStackTrace();
		}
		return obj;
	}

}
           

詳細的介紹請參考:Faster Deep Copies of Java Objects: http://javatechniques.com/blog/faster-deep-copies-of-java-objects/. 裡面還提供了上述方法的優化實作。

當然這還有一種變體,除了把對象序列化成一個stream之外,還可以将其序列化成一個xml。利用Xstream這個包可以很容易地實作。

2、一些專門的開源包,連實作Serializable接口都不需要了。

Java generic deep copy: http://www.genericdeepcopy.com/

Java deep-cloning library: http://code.google.com/p/cloning/