最近在做标签系统时,为提高查询效率,使用了内存map,在初始化时将数据查询放在内存中,在查询时,不再去查数据库,而是使用map中的数据进行关联查询。在使用内存时,有时需要对查询结果重新赋值,如某些没有权限的字段需要赋值“暂无权限”等,就出现了内存会被修改的问题。
1、简单介绍下深拷贝和浅拷贝
浅拷贝:只复制对象的引用,两个引用仍然指向同一个对象,在内存中占用同一块内存;
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象;
换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
深拷贝:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量;
那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象;
换言之,深复制把要复制的对象所引用的对象都复制了一遍
2、再说说我们遇到的问题,在对对象进行=赋值,或者clone时候一般都是我们所说的浅复制,Object T1= T2;也就是说我们获取的并非在堆中重新分配的一块内存,而是一个指向原有数据内存的一个引用。这样的后果就是我们修改了T1中的属性,那么T2的属性也会同时发生变化,因为他们两个本身就指向同一个对象,所以变化一个另外一个也随着变化。
一般来说我们常用的解决写法是:在Map中提供的一个putAll方法,可以部分解决这个问题,(为什么说是部分呢?因为putAll方法只能对基本数据类型进行深复制,对于对象类型完全也是无力),那么就需一个更好的解决方案来进行对象的深复制
有一个方法是,使用序列化Serializable这个接口可以完成深拷贝的操作,但遗憾的是Map对象并没有实现Serializable接口,不能直接对接口进行深复制操作。
但是作为Map的子类,HashMap实现了Serialization,因此可以通过以下的方式实现深复制。
下面简单说说java 深拷贝map 深度复制map可以用的解决方法
方法1使用依赖:
使用jar包commons-lang-2.4.jar中的 SerializationUtils.clone() 方法
方法2写工具方法
class CloneUtils{
@SuppressWarnings("unchecked")
public static < T extends Serializable > T clone(T obj){
T cloneObj=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);
//返回新的对象,并做类型转换
cloneObj=(T)ois.readObject();
ois.close();
}catch(Exception e){
e.printStackTrace();
}
return cloneObj;
}
}