Java深拷贝和浅拷贝Map对象

简介: 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为对象时,是不会奏效的

简单的说就是被拷贝的对象改变是否影响源对象,影响就是浅拷贝,不影响就是深拷贝。


目录
相关文章
|
2月前
|
存储 安全 Java
Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
【10月更文挑战第17天】Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
80 2
|
1月前
|
安全 Java 编译器
Java对象一定分配在堆上吗?
本文探讨了Java对象的内存分配问题,重点介绍了JVM的逃逸分析技术及其优化策略。逃逸分析能判断对象是否会在作用域外被访问,从而决定对象是否需要分配到堆上。文章详细讲解了栈上分配、标量替换和同步消除三种优化策略,并通过示例代码说明了这些技术的应用场景。
Java对象一定分配在堆上吗?
|
2月前
|
Java API
Java 对象释放与 finalize 方法
关于 Java 对象释放的疑惑解答,以及 finalize 方法的相关知识。
54 17
|
1月前
|
存储 Java API
Java交换map的key和value值
通过本文介绍的几种方法,可以在Java中实现Map键值对的交换。每种方法都有其优缺点,具体选择哪种方法应根据实际需求和场景决定。对于简单的键值对交换,可以使用简单遍历法或Java 8的Stream API;对于需要处理值不唯一的情况,可以使用集合存储或Guava的Multimap。希望本文对您理解和实现Java中的Map键值对交换有所帮助。
42 1
|
1月前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第22天】在Java的世界里,对象序列化和反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何在Java中实现对象的序列化与反序列化,并探讨其背后的原理。通过实际代码示例,我们将一步步展示如何将复杂数据结构转换为字节流,以及如何将这些字节流还原为Java对象。文章还将讨论在使用序列化时应注意的安全性问题,以确保你的应用程序既高效又安全。
|
2月前
|
存储 安全 Java
从入门到精通:Java Map全攻略,一篇文章就够了!
【10月更文挑战第19天】本文介绍了Java编程中重要的数据结构——Map,通过问答形式讲解了Map的基本概念、创建、访问与修改、遍历方法、常用实现类(如HashMap、TreeMap、LinkedHashMap)及其特点,以及Map在多线程环境下的使用和性能优化技巧,适合初学者和进阶者学习。
86 4
|
2月前
|
存储 Java API
优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。
【10月更文挑战第19天】本文介绍了如何优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。内容包括Map的初始化、使用Stream API处理Map、利用merge方法、使用ComputeIfAbsent和ComputeIfPresent,以及Map的默认方法。这些技巧不仅提高了代码的可读性和维护性,还提升了开发效率。
101 3
|
2月前
|
存储 Java API
详细解析HashMap、TreeMap、LinkedHashMap等实现类,帮助您更好地理解和应用Java Map。
【10月更文挑战第19天】深入剖析Java Map:不仅是高效存储键值对的数据结构,更是展现设计艺术的典范。本文从基本概念、设计艺术和使用技巧三个方面,详细解析HashMap、TreeMap、LinkedHashMap等实现类,帮助您更好地理解和应用Java Map。
71 3
|
2月前
|
存储 缓存 安全
在Java的Map家族中,HashMap和TreeMap各具特色
【10月更文挑战第19天】在Java的Map家族中,HashMap和TreeMap各具特色。HashMap基于哈希表实现,提供O(1)时间复杂度的高效操作,适合性能要求高的场景;TreeMap基于红黑树,提供O(log n)时间复杂度的有序操作,适合需要排序和范围查询的场景。两者在不同需求下各有优势,选择时需根据具体应用场景权衡。
39 2
|
2月前
|
存储 安全 Java
Java Map新玩法:深入探讨HashMap和TreeMap的高级特性
【10月更文挑战第19天】Java Map新玩法:深入探讨HashMap和TreeMap的高级特性,包括初始容量与加载因子的优化、高效的遍历方法、线程安全性处理以及TreeMap的自然排序、自定义排序、范围查询等功能,助你提升代码性能与灵活性。
31 2