List、Map深拷贝
在java中有一个比较有趣的特性,在对对象进行=赋值,或者clone时候一般都是我们所说的浅复制,
Object A = B;
也就是说我们获取的并非在堆中重新分配的一块内存,而是一个指向原有数据内存的一个引用。
这样的后果就是我们修改了A中的属性,那么B的属性也会同时发生变化,因为他们两个本身就指向同一个对象,所以变化一个另外一个也随着变化。
在Map中提供的一个putAll方法,可以部分解决这个问题,(为什么是部分呢?因为putAll方法只能对基本数据类型进行深复制,对于对象类型完全也是无力),因此急需一个好的解决方案来进行对象的深复制
有一个方法是,使用序列化Serializable这个接口可以完成深拷贝的操作,但遗憾的是Map对象并没有实现Serializable接口,不能直接对接口进行深复制操作。
public interface Map<K,V> {...}
但是作为Map的子类,HashMap实现了Serialization,因此可以通过以下的方式实现深复制。
/**
* map对非基本数据类型的深拷贝
* @param obj
* @param <T>
* @return
*/
@SuppressWarnings("unchecked")
public static <T extends Serializable> T deepCopymap(T obj) throws IOException, ClassNotFoundException{
T clonedObj = null;
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
clonedObj = (T) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
return clonedObj;
}
同理,list的拷贝原理如上,对其深拷贝的方法之一如下:
/**
* list深拷贝
* @param src
* @param <T>
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
public static <T> List<T> deepCopylist(List<T> src) throws IOException, ClassNotFoundException {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(src);
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream in = new ObjectInputStream(byteIn);
@SuppressWarnings("unchecked")
List<T> dest = (List<T>) in.readObject();
return dest;
}