首页 > 分享 > Map复制给新Map时,用 “=、clone、还是putAll”?论Map的深复制和浅复制

Map复制给新Map时,用 “=、clone、还是putAll”?论Map的深复制和浅复制

目录 使用场景尝试过的办法1. “=”赋值2. 使用.putAll()方法3. 使用.clone()方法 测试用例测试用例源码

使用场景

在我们最初使用map复制开发业务代码时,通常会踩到深浅复制(拷贝)这个坑里,比如我,在Map复制时
(如:Map<String, String> new_Map = old_Map) 出现过以下两类问题:

1.使用Map<String, String> new_Map = old_Map 操作,当修改new_Map属性后,old_Map属性也跟着变了,但我并没有修改过old_Map
2.由于Map中的value值不仅有基本数据类型,还有引用数据类型,所以当我修改引用类型属性后,new_Map和old_Map的引用变量值都发生变化;(如你的value都是基本类型,就不涉及深浅拷贝的问题)

尝试过的办法

1. “=”赋值

新建一个Map,然后使用“=”直接赋值,这样只是复制了old_Map的引用,和old_Map仍使用同一个内存区域,所以,在修改new_Map的时候,old_Map的值同样会发生变化。

<Map<String, String> new_Map = old_Map> 1

上述的办法不行,使用Map本身提供的方法,网上大都说putAll()和clone()方法就是深拷贝,但是实际使用后,发现前后Map中的引用对象还是都被改变了;这里就是开头说到的,这两个方法只能修改基本数据类型的,如果是引用类型不行,这两个方法是浅拷贝!

来,让我们一起跟一下源码↓↓↓

2. 使用.putAll()方法

创建一个新的Map结构,使用putAll()方法把原先的Map添加到新的Map中,但是发现修改了副本的Map之后,原先的Map中数据也被修改了;(源码如下)

public void putAll(Map<? extends K, ? extends V> m) { putMapEntries(m, true); // 调用了putMapEntries方法 }final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) { int s = m.size(); if (s > 0) { if (table == null) { // pre-size float ft = ((float)s / loadFactor) + 1.0F; int t = ((ft < (float)MAXIMUM_CAPACITY) ? (int)ft : MAXIMUM_CAPACITY); if (t > threshold) threshold = tableSizeFor(t); } else if (s > threshold) resize(); for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) { K key = e.getKey(); V value = e.getValue(); putVal(hash(key), key, value, false, evict); // 循环调用了value,但value中的引用对象指针并没有改变。 // 扩展:map.put("key","value")的put()也是调用了putVal()方法 } } }

123456789101112131415161718192021222324

3. 使用.clone()方法

HashMap自带了一个clone()方法,但是,它的源码中注释说明了也只是一种浅复制(拷贝):(源码如下)

@Override public Object clone() { HashMap<K,V> result; try { result = (HashMap<K,V>)super.clone(); } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(e); } result.reinitialize(); // 清空map result.putMapEntries(this, false); // 可见,和putAll调用了同一个接口, return result; } final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) { int s = m.size(); if (s > 0) { if (table == null) { // pre-size float ft = ((float)s / loadFactor) + 1.0F; int t = ((ft < (float)MAXIMUM_CAPACITY) ? (int)ft : MAXIMUM_CAPACITY); if (t > threshold) threshold = tableSizeFor(t); } else if (s > threshold) resize(); for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) { K key = e.getKey(); V value = e.getValue(); putVal(hash(key), key, value, false, evict); // 同上,循环调用了“value”,value中的引用对象指针并没有改变 } } }

12345678910111213141516171819202122232425262728293031323334

测试用例

List<Integer> list = new ArrayList<Integer>(); list.add(100); list.add(200); HashMap<String,Object> old_map = new HashMap<String,Object>(); old_map.put("name", "蔡虚坤");//放基本类型数据 old_map.put("list", list);//放对象 HashMap<String,Object> new_map = new HashMap<String,Object>(); new_map.putAll(old_map); System.out.println("----基础数据展示-----"); System.out.println("old: " + old_map); System.out.println("new: " + new_map); System.out.println("----更改基本数据类型的数据-----"); old_map.put("name", "娘炮"); System.out.println("old: " + old_map); System.out.println("new: " + new_map); System.out.println("----更改引用类型的数据-----"); list.add(300); System.out.println("old: " + old_map); System.out.println("new: " + new_map); System.out.println("----使用序列化进行深拷贝 自定义Clone方法-----"); new_map = myClone(old_map); // myClone() 方法源码在下方 ↓↓ list.add(400); System.out.println("old: " + old_map); System.out.println("new: " + new_map); 输出结果: Connected to the target VM, address: '127.0.0.1:58242', transport: 'socket' ----基础数据展示----- old: {name=蔡虚坤, list=[100, 200]} new: {name=蔡虚坤, list=[100, 200]} ----更改基本数据类型的数据----- old: {name=娘炮, list=[100, 200]} new: {name=蔡虚坤, list=[100, 200]} ----更改引用类型的数据----- old: {name=娘炮, list=[100, 200, 300]} new: {name=蔡虚坤, list=[100, 200, 300]} ----使用序列化进行深拷贝----- old: {name=娘炮, list=[100, 200, 300, 400]} new: {name=娘炮, list=[100, 200, 300]}

123456789101112131415161718192021222324252627282930313233343536373839404142

#最上面的两条是原始数据,使用了putAll方法拷贝了一个新的new_map对象,
#中间两条,是修改old_map对象的基本数据类型的时候,并没有影响到new_map对象。
#但是看倒数第二组,更改引用数据类型的时候,发现new_map的值也变化了,所以putAll并没有对old_map产生深拷贝。
#最后面是使用序列化的方式,发现,更改引用类型的数据的时候,new_map对象并没有发生变化,所以产生了深拷贝。(下方提供自定义clone方法源码)
#上述的工具类,可以实现对象的深拷贝,不仅限于HashMap,前提是实现了Serlizeable接口。

测试用例源码

package com.softsec.demo; import java.io.*; import java.util.*; public class demoMap implements Cloneable{ public static void main(String[] srag) { List<Integer> list = new ArrayList<Integer>(); list.add(100); list.add(200); HashMap<String,Object> old_map = new HashMap<String,Object>(); old_map.put("name", "蔡虚坤");//放基本类型数据 old_map.put("list", list);//放对象 HashMap<String,Object> new_map = new HashMap<String,Object>(); new_map.putAll(old_map); System.out.println("----基础数据展示-----"); System.out.println("old:" + old_map); System.out.println("new:" + new_map); System.out.println("----更改基本数据类型的数据-----"); old_map.put("name", "娘炮"); System.out.println("old:" + old_map); System.out.println("new:" + new_map); System.out.println("----更改引用类型的数据-----"); list.add(300); System.out.println("old:" + old_map); System.out.println("new:" + new_map); System.out.println("----使用序列化进行深拷贝 自定义Clone方法-----"); new_map = myClone(old_map); list.add(400); System.out.println("old:" + old_map); System.out.println("new:" + new_map); } /** * 自定义clone方法(对象必须是实现了Serializable接口) * */ public static <T extends Serializable> T myClone(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; } }

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162

相关知识

Seed Map
《MAP慧农》如何进行农作物病虫害监测?
营销自动化 MAP,品牌新势力的下一个增长点
MAP:给现代农业装上智慧大脑——中化集团建立农业现代化优质范本的探索之路
花卉地图 (Flower Map)
华为花瓣地图(Petal map)app下载
C语言玫瑰花代码/源码免费复制/炫酷红玫瑰
花卉避免自我复制杂交方法
复制空间高清图片
Ningbo atmospheric environment analysis and regulating countermeasure based on Urban Climatic Map

网址: Map复制给新Map时,用 “=、clone、还是putAll”?论Map的深复制和浅复制 https://m.huajiangbk.com/newsview1146462.html

所属分类:花卉
上一篇: 长辈头像图片
下一篇: 关于送老公父亲节的祝福语(精选1