天天看点

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/