map复制 java_Map拷贝 关于对象深拷贝 浅拷贝的问题

本文详细介绍了Java中Map的浅拷贝与深拷贝概念,通过实例展示了浅拷贝导致的引用问题,并提供了使用putAll()方法和序列化方式实现深拷贝的方法。在讲解过程中,强调了putAll()方法并不能实现深拷贝,特别是在涉及到引用类型数据时。文章最后给出了序列化实现深拷贝的工具类及其使用示例,证明了序列化拷贝能有效避免引用数据类型的变动影响到拷贝后的对象。
摘要由CSDN通过智能技术生成

本文地址:http://www.dutycode.com/map_kaobei_shenkaobei_qiankaobei.html

除非注明,文章均为 www.dutycode.com 原创,欢迎转载!转载请注明本文地址,谢谢。

问题:map拷贝时发现数据会变化。

高能预警,你看到的下面的栗子是不正确的,后面有正确的一种办法,如果需要看的话的,请看到底,感谢各同学的提醒,已做更正,一定要看到最后

先看例子:

public class CopyMap {

/**

* @author 张仲华

* @param args

* 2014 -8 -6 上午9:29:33

*/

public static void main(String[] args) {

Map map = new HashMap();

map.put( "key1", 1);

Map mapFirst = map;

System. out.println( mapFirst);

map.put( "key2", 2);

System. out.println( mapFirst);

}

}

上面程序的期望输出值是,mapFrist的值均为1,

但是实际上输出结果为:

{key1=1}

{key2=2, key1=1}

这里是因为map发生了浅拷贝,mapFirst只是复制了map的引用,和map仍使用同一个内存区域,所以,在修改map的时候,mapFirst的值同样会发生变化。

PS:

所谓浅复制:则是只复制对象的引用,两个引用仍然指向同一个对象,在内存中占用同一块内存。被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

深复制:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

如何解决?

使用深拷贝,拷贝整个对象,而非引用

Map中有个方法叫做putAll方法,可以实现深拷贝,如下:

publicclass CopyMap {

/**

*@author张仲华

*@paramargs

* 2014 -8 -6 上午9:29:33

*/

publicstaticvoidmain(String[] args) {

Map map =newHashMap();

map.put( "key1", 1);

Map mapFirst =newHashMap();

mapFirst.putAll(map); //深拷贝

System. out.println(mapFirst);

map.put( "key2", 2);

System. out.println(mapFirst);

}

}

如上,输出结果为:

{key1=1}

{key1=1}

参考:http://blog.csdn.net/lzkkevin/article/details/6667958

注意!!!注意!!!!注意!!! 上面并不是深拷贝,留下来的原因是提醒大家,这里是存在错误的。(很高兴你看到这里了)

感谢下面这几位朋友的提醒。

d8fbcb2ccf1aad68e50c6ce7d4a66cfe.png2ec30a205dc6917a90de33bfad6abbe1.png

文章更正如下:

如何实现Map的深拷贝呢?

有一种方法,是使用序列化的方式来实现对象的深拷贝,但是前提是,对象必须是实现了

Serializable接口才可以,Map本身没有实现

Serializable 这个接口,所以这种方式不能序列化Map,也就是不能深拷贝Map。但是HashMap是可以的,因为它实现了

Serializable。下面的方式,基于HashMap来讲,非Map的拷贝。

具体实现如下:

public class CloneUtils {

@SuppressWarnings("unchecked")

public static T clone(T obj){

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;

}

}

如何使用呢,下面是个使用的例子,同时证明了Map的putAll方法并没有实现深拷贝,putAll仅对基本数据类型起到深拷贝的作用。

栗子:

public static void main(String[] args) {

List list = new ArrayList();

list.add(100);

list.add(200);

HashMap map = new HashMap();

//放基本类型数据

map.put("basic", 100);

//放对象

map.put("list", list);

HashMap mapNew = new HashMap();

mapNew.putAll(map);

System.out.println("----数据展示-----");

System.out.println(map);

System.out.println(mapNew);

System.out.println("----更改基本类型数据-----");

map.put("basic", 200);

System.out.println(map);

System.out.println(mapNew);

System.out.println("----更改引用类型数据-----");

list.add(300);

System.out.println(map);

System.out.println(mapNew);

System.out.println("----使用序列化进行深拷贝-----");

mapNew = CloneUtils.clone(map);

list.add(400);

System.out.println(map);

System.out.println(mapNew);

}

输出结果如下:

be992b1e5b73b7e87e96bd659936d741.png

最上面的两条是原始数据,使用了putAll方法拷贝了一个新的mapNew对象,

中间两条,是修改map对象的基本数据类型的时候,并没有影响到mapNew对象。

但是看倒数第二组,更改引用数据类型的时候,发现mapNew的值也变化了,所以putAll并没有对map产生深拷贝。

最后面是使用序列化的方式,发现,更改引用类型的数据的时候,mapNew对象并没有发生变化,所以产生了深拷贝。

上述的工具类,可以实现对象的深拷贝,不仅限于HashMap,前提是实现了Serlizeable接口。

还没有看putAll的源码实现,后面看下为什么不能实现深拷贝。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值