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

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


目录
相关文章
|
5月前
|
Java
深入JavaSE:详解Java对象的比较。
总的来说,Java对象的比较就像海洋生物的比较,有外在的,有内在的,有面对所有情况的,也有针对特殊情况的。理解并掌握这些比较方式,就能更好地驾驭Java的世界,游刃有余地操作Java对象。
94 12
|
6月前
|
编解码 JavaScript 前端开发
【Java进阶】详解JavaScript的BOM(浏览器对象模型)
总的来说,BOM提供了一种方式来与浏览器进行交互。通过BOM,你可以操作窗口、获取URL、操作历史、访问HTML文档、获取浏览器信息和屏幕信息等。虽然BOM并没有正式的标准,但大多数现代浏览器都实现了相似的功能,因此,你可以放心地在你的JavaScript代码中使用BOM。
183 23
|
5月前
|
安全 Java API
【Java性能优化】Map.merge()方法:告别繁琐判空,3行代码搞定统计累加!
在日常开发中,我们经常需要对Map中的值进行累加统计。}else{代码冗长,重复调用get()方法需要显式处理null值非原子操作,多线程下不安全今天要介绍的方法,可以让你用一行代码优雅解决所有这些问题!方法的基本用法和优势与传统写法的对比分析多线程安全版本的实现Stream API的终极优化方案底层实现原理和性能优化建议一句话总结是Java 8为我们提供的Map操作利器,能让你的统计代码更简洁、更安全、更高效!// 合并两个列表});简单累加。
486 0
|
6月前
|
Java 数据安全/隐私保护
Java 类和对象
本文介绍了Java编程中类和对象的基础知识,作为面向对象编程(OOP)的核心概念。类是对象的蓝图,定义实体类型;对象是具体实例,包含状态和行为。通过示例展示了如何创建表示汽车的类及其实例,并说明了构造函数、字段和方法的作用。同时,文章还探讨了访问修饰符的使用,强调封装的重要性,如通过getter和setter控制字段访问。最后总结了类与对象的关系及其在Java中的应用,并建议进一步学习继承等概念。
134 1
|
7月前
|
人工智能 安全 Java
深入理解Java浅拷贝与深拷贝
本文深入探讨Java中浅拷贝与深拷贝的概念、实现方式及应用场景。浅拷贝通过`clone()`方法复制对象引用,修改新对象会影响原对象;深拷贝则创建完全独立的新对象,确保数据安全。文章通过代码示例讲解两种拷贝方式的实现,并分析其优缺点。同时,针对List类型提供浅拷贝和深拷贝的具体实现方法,帮助读者更好地理解和应用这两种技术。选择拷贝方式时需权衡对象复杂度、大小及操作安全性等因素。
397 2
|
7月前
|
设计模式 缓存 Java
重学Java基础篇—Java对象创建的7种核心方式详解
本文全面解析了Java中对象的创建方式,涵盖基础到高级技术。包括`new关键字`直接实例化、反射机制动态创建、克隆与反序列化复用对象,以及工厂方法和建造者模式等设计模式的应用。同时探讨了Spring IOC容器等框架级创建方式,并对比各类方法的适用场景与优缺点。此外,还深入分析了动态代理、Unsafe类等扩展知识及注意事项。最后总结最佳实践,建议根据业务需求选择合适方式,在灵活性与性能间取得平衡。
408 3
|
6月前
|
存储 缓存 Java
理解Java引用数据类型:它们都是对象引用
本文深入探讨了Java中引用数据类型的本质及其相关特性。引用变量存储的是对象的内存地址而非对象本身,类似房子的地址而非房子本身。文章通过实例解析了引用赋值、比较(`==`与`equals()`的区别)以及包装类缓存机制等核心概念。此外,还介绍了Java引用类型的家族,包括类、接口、数组和枚举。理解这些内容有助于开发者避免常见错误,提升对Java内存模型的掌握,为高效编程奠定基础。
318 0
|
6月前
|
Java
java中一个接口A,以及一个实现它的类B,一个A类型的引用对象作为一个方法的参数,这个参数的类型可以是B的类型吗?
本文探讨了面向对象编程中接口与实现类的关系,以及里氏替换原则(LSP)的应用。通过示例代码展示了如何利用多态性将实现类的对象传递给接口类型的参数,满足LSP的要求。LSP确保子类能无缝替换父类或接口,不改变程序行为。接口定义了行为规范,实现类遵循此规范,从而保证了多态性和代码的可维护性。总结来说,接口与实现类的关系天然符合LSP,体现了多态性的核心思想。
135 0
|
存储 Java
java集合框架------Map接口与实现类
java集合框架------Map接口与实现类
107 0
|
12月前
|
存储 Java 开发者
Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效
【10月更文挑战第19天】在软件开发中,随着项目复杂度的增加,数据结构的组织和管理变得至关重要。Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,帮助开发者告别混乱,提升代码质量。
121 1
下一篇
oss教程