1 将Map深拷贝到另一个Map对象当中
今天赋值的时候遇到的小坑
1.相关文章推荐:
Java克隆方式避免频繁创建对象优化方案 https://blog.csdn.net/ZGL_cyy/article/details/126556907
2.代码实现
import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * 复制map对象 * @explain 将paramsMap中的键值对全部拷贝到resultMap中; * paramsMap中的内容不会影响到resultMap(深拷贝) * @param paramsMap * 被拷贝对象 * @param resultMap * 拷贝后的对象 */ public static void mapCopy(Map paramsMap, Map resultMap) { if (resultMap == null) resultMap = new HashMap(); if (paramsMap == null) return; Iterator it = paramsMap.entrySet().iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); Object key = entry.getKey(); resultMap.put(key, paramsMap.get(key) != null ? paramsMap.get(key) : ""); } }
3.测试
public class TestDemo { public static void main(String[] args) { Map<String, String> map = new HashMap<String, String>(1); map.put("name", "oldlu"); Map<String, Object> map2 = new HashMap<String, Object>(1); map2.put("age", new Integer(28)); // 测试一:是否实现拷贝 mapCopy(map2, map); System.out.println(map); System.out.println(map2); // 测试二:拷贝后的map对象是否受原map对象的影响 map2.clear(); System.out.println(map); System.out.println(map2); } }
结果如图
回复下方评论
public static void main(String[] args) { Map<String, String> map = new HashMap<String, String>(1); map.put("name", "oldlu"); Map<String, Object> map2 = new HashMap<String, Object>(1); map2.put("age", new Integer(28)); // 测试一:是否实现拷贝 mapCopy(map2, map); System.out.println(map); System.out.println(map2); // 测试二:拷贝后的map对象是否受原map对象的影响 // map2.clear(); map.clear(); System.out.println(map); System.out.println(map2); } public static void mapCopy(Map paramsMap, Map resultMap) { if (resultMap == null) resultMap = new HashMap(); if (paramsMap == null) return; Iterator it = paramsMap.entrySet().iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); Object key = entry.getKey(); resultMap.put(key, paramsMap.get(key) != null ? paramsMap.get(key) : ""); } }
测试结果
第一种是深拷贝么?你把原来的map clear一下会不会影响copy的map,并不会,Iterator复制的map则不受源map改变的影响,iterator遍历添加的方式,由于是重新创建了一个对象,且遍历添加源Map的元素,因此在内存中另开辟了一块内存是深拷贝;
2 Map的两种拷贝类型
Map的拷贝分为两种情况:
浅拷贝:只拷贝对象的引用,两个引用仍然指向同一个对象,在内存中占用同一块内存。被拷贝对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。即浅拷贝仅仅拷贝对象的引用,而不拷贝它所引用的对象。
深拷贝:被拷贝对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被拷贝过的新对象,而不再是原有的那些被引用的对象。即深拷贝把要拷贝的对象所引用的对象都拷贝了一遍。
针对map中的数据为统一的、简单的基本数据类型,当拷贝的数据通过『 = 』复制map的方法为浅拷贝,在 Java 中,除了基本数据类型(元类型)之外,还存在类的实例对 这个引用数据类型。而一般使用 『 = 』号做赋值操作的时候。对于基本数据类型,实际上是拷贝的它的值,但是对于对象而言,其实赋值的只是这个对象的引用,将原对象的引用传递过去,他们实际上还是指向的同一个对象。putAll方法为深拷贝,iterator遍历添加的方式为深拷贝。
3 浅拷贝Map
1 测试代码
public class TestDemo { public static void main(String[] args) { // 赋值操作:=只能实现浅拷贝,map中的内容发生变化,copyMap中的内容亦同步发生变化 Map<String, String> map = new HashMap<String, String>(1); map.put("name", "oldlu"); Map<String, String> copyMap = new HashMap<String, String>(1); // 实现浅拷贝的方式:使用= copyMap = map; map.remove("name"); System.out.println("map:" + map); System.out.print("copyMap:" + copyMap); } }
测试结果
2 使用putAll方法
强调:简单的基本数据类型,putAll方法为深拷贝
public class TestDemo { public static void main(String[] args) { Map<String, Object> map = new HashMap<>(); Map<String, Object> mapCopy = new HashMap<>(); Map mapInner = new HashMap(); mapInner.put("num", 100); map.put("key1", mapInner); map.put("key2", 200); mapCopy.putAll(map); System.out.println(map); System.out.println(mapCopy); ((Map) mapCopy.get("key1")).put("num", 300); map.put("key2", 300); System.out.println(mapCopy); System.out.println(map); } }
运行结果
也就是说两个map如果存的是对象putAll指向同一块内存,当内存的对象发生变化都会变化,,所以是浅拷贝,但是当你put新对象但是key相同的时候他两就不是指向同一块区域了,就是完全独立的两个map,本来想简单写写这个简单的文章,也是看到回复对于这块知识有所欠缺所以好好写一下。
putAll() 源码
/** * Copies all of the mappings from the specified map to this map. * These mappings will replace any mappings that this map had for * any of the keys currently in the specified map. * * @param m mappings to be stored in this map * @throws NullPointerException if the specified map is null */ public void putAll(Map<? extends K, ? extends V> m) { int numKeysToBeAdded = m.size(); if (numKeysToBeAdded == 0) return; /* * Expand the map if the map if the number of mappings to be added * is greater than or equal to threshold. This is conservative; the * obvious condition is (m.size() + size) >= threshold, but this * condition could result in a map with twice the appropriate capacity, * if the keys to be added overlap with the keys already in this map. * By using the conservative calculation, we subject ourself * to at most one extra resize. */ if (numKeysToBeAdded > threshold) { int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1); if (targetCapacity > MAXIMUM_CAPACITY) targetCapacity = MAXIMUM_CAPACITY; int newCapacity = table.length; while (newCapacity < targetCapacity) newCapacity <<= 1; if (newCapacity > table.length) resize(newCapacity); } for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) put(e.getKey(), e.getValue()); }
通过源码可以看到putAll() 方法的实现仅仅是将源Map的第一层put进Map中,这种方式对于value为基本类型的map复制是实现深拷贝的效果的,但是当value为对象时,是不会奏效的
简单的说就是被拷贝的对象改变是否影响源对象,影响就是浅拷贝,不影响就是深拷贝。