Java深拷贝和浅拷贝Map对象
Posted 赵广陆
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java深拷贝和浅拷贝Map对象相关的知识,希望对你有一定的参考价值。
目录
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为对象时,是不会奏效的
简单的说就是被拷贝的对象改变是否影响源对象,影响就是浅拷贝,不影响就是深拷贝。
以上是关于Java深拷贝和浅拷贝Map对象的主要内容,如果未能解决你的问题,请参考以下文章