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对象的主要内容,如果未能解决你的问题,请参考以下文章

深拷贝和浅拷贝的区别?

jquery怎样深拷贝一个数组

深入浅出:了解深拷贝和浅拷贝

Java中的深拷贝(深复制)和浅拷贝(浅复制)

python的深拷贝和浅拷贝

Java中的深拷贝和浅拷贝(转载)