map复制,可不是简单的=就行了! Map的深 浅拷贝

目录

使用场景

在我们最初使用map复制开发业务代码时,通常会踩到深浅复制(拷贝)这个坑里,比如我,在Map复制时
(如:Map<String, String> new_Map = old_Map) 出现过以下两类问题:

1.使用Map<String, String> new_Map = old_Map 操作,当修改new_Map属性后,old_Map属性也跟着变了,但我并没有修改过old_Map
2.由于Map中的value值不仅有基本数据类型,还有引用数据类型,所以当我修改引用类型属性后,new_Map和old_Map的引用变量值都发生变化;(如你的value都是基本类型,就不涉及深浅拷贝的问题)

尝试过的办法

1. “=”赋值

新建一个Map,然后使用“=”直接赋值,这样只是复制了old_Map的引用,和old_Map仍使用同一个内存区域,所以,在修改new_Map的时候,old_Map的值同样会发生变化。

<Map<String, String> new_Map = old_Map>

   
   

    3. 使用.clone()方法

    HashMap自带了一个clone()方法,但是,它的源码中注释说明了也只是一种浅复制(拷贝):(源码如下)

    	@Override
        public Object clone() {
            HashMap<K,V> result;
            try {
                result = (HashMap<K,V>)super.clone();
            } catch (CloneNotSupportedException e) {
                // this shouldn't happen, since we are Cloneable
                throw new InternalError(e);
            }
            result.reinitialize(); // 清空map
            result.putMapEntries(this, false);  // 可见,和putAll调用了同一个接口,
            return result;
        }
    
        final void putMapEntries(Map&lt;? extends K, ? extends V&gt; m, boolean evict) {
        int s = m.size();
        if (s &gt; 0) {
            if (table == null) { // pre-size
                float ft = ((float)s / loadFactor) + 1.0F;
                int t = ((ft &lt; (float)MAXIMUM_CAPACITY) ?
                         (int)ft : MAXIMUM_CAPACITY);
                if (t &gt; threshold)
                    threshold = tableSizeFor(t);
            }
            else if (s &gt; threshold)
                resize();
            for (Map.Entry&lt;? extends K, ? extends V&gt; e : m.entrySet()) {
                K key = e.getKey();
                V value = e.getValue();
                putVal(hash(key), key, value, false, evict); // 同上,循环调用了“value”,value中的引用对象指针并没有改变
            }
        }
    }
    

    测试用例

    List<Integer> list = new ArrayList<Integer>();
    list.add(100);
    list.add(200);
    

    HashMap<String,Object> old_map = new HashMap<String,Object>();
    old_map.put(“name”, “蔡虚坤”);//放基本类型数据
    old_map.put(“list”, list);//放对象

    HashMap<String,Object> new_map = new HashMap<String,Object>();

    new_map.putAll(old_map);
    System.out.println(“----基础数据展示-----”);
    System.out.println(“old: " + old_map);
    System.out.println(“new: " + new_map);
    System.out.println(”----更改基本数据类型的数据-----”);
    old_map.put(“name”, “娘炮”);
    System.out.println(“old: " + old_map);
    System.out.println(“new: " + new_map);
    System.out.println(”----更改引用类型的数据-----”);
    list.add(300);
    System.out.println(“old: " + old_map);
    System.out.println(“new: " + new_map);
    System.out.println(”----使用序列化进行深拷贝 自定义Clone方法-----”);
    new_map = myClone(old_map); // myClone() 方法源码在下方 ↓↓
    list.add(400);
    System.out.println("old: " + old_map);
    System.out.println("new: " + new_map);

    输出结果:
    Connected to the target VM, address: ‘127.0.0.1:58242’, transport: ‘socket’
    ----基础数据展示-----
    old: {name=蔡虚坤, list=[100, 200]}
    new: {name=蔡虚坤, list=[100, 200]}
    ----更改基本数据类型的数据-----
    old: {name=娘炮, list=[100, 200]}
    new: {name=蔡虚坤, list=[100, 200]}
    ----更改引用类型的数据-----
    old: {name=娘炮, list=[100, 200, 300]}
    new: {name=蔡虚坤, list=[100, 200, 300]}
    ----使用序列化进行深拷贝-----
    old: {name=娘炮, list=[100, 200, 300, 400]}
    new: {name=娘炮, list=[100, 200, 300]}

    #最上面的两条是原始数据,使用了putAll方法拷贝了一个新的new_map对象,
    #中间两条,是修改old_map对象的基本数据类型的时候,并没有影响到new_map对象。
    #但是看倒数第二组,更改引用数据类型的时候,发现new_map的值也变化了,所以putAll并没有对old_map产生深拷贝。
    #最后面是使用序列化的方式,发现,更改引用类型的数据的时候,new_map对象并没有发生变化,所以产生了深拷贝。(下方提供自定义clone方法源码)
    #上述的工具类,可以实现对象的深拷贝,不仅限于HashMap,前提是实现了Serlizeable接口。

    测试用例源码

    package com.softsec.demo;
    

    import java.io.;
    import java.util.
    ;

    public class demoMap implements Cloneable{

    public static void main(String[] srag) {
        List&lt;Integer&gt; list = new ArrayList&lt;Integer&gt;();
        list.add(100);
        list.add(200);
    
        HashMap&lt;String,Object&gt; old_map = new HashMap&lt;String,Object&gt;();
        old_map.put("name", "蔡虚坤");//放基本类型数据
        old_map.put("list", list);//放对象
    
        HashMap&lt;String,Object&gt; new_map = new HashMap&lt;String,Object&gt;();
    
        new_map.putAll(old_map);
        System.out.println("----基础数据展示-----");
        System.out.println("old:" + old_map);
        System.out.println("new:" + new_map);
        System.out.println("----更改基本数据类型的数据-----");
        old_map.put("name", "娘炮");
        System.out.println("old:" + old_map);
        System.out.println("new:" + new_map);
        System.out.println("----更改引用类型的数据-----");
        list.add(300);
        System.out.println("old:" + old_map);
        System.out.println("new:" + new_map);
        System.out.println("----使用序列化进行深拷贝 自定义Clone方法-----");
        new_map = myClone(old_map);
        list.add(400);
        System.out.println("old:" + old_map);
        System.out.println("new:" + new_map);
    }
    
    /**
     * 自定义clone方法(对象必须是实现了Serializable接口)
     *
     */
    public static &lt;T extends Serializable&gt; T myClone(T obj) {
        T clonedObj = null;
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(obj);
            oos.close();
    
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            clonedObj = (T) ois.readObject();
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return clonedObj;
    }
    
    • 0
      点赞
    • 3
      收藏
      觉得还不错? 一键收藏
    • 0
      评论
    在Go语言中,map是一种引用类型,所赋值操作会进拷贝,即只会复制指向底层数据的指针,并不会复制底层数据本身。如果需要进拷贝,可以通过以下方法实现: 1. 手动复制元素: - 创建一个新的空map。 - 遍历原始map的键值对,将每个键值对复制到新map中。 - 这样就创建了一个新的map,其中的键值对是原始map中键值对的副本。 示例代码: ```go originalMap := map[string]int{"a": 1, "b": 2, "c": 3} // 进拷贝 newMap := make(map[string]int) for key, value := range originalMap { newMap[key] = value } // 修改原始map的值 originalMap["a"] = 100 fmt.Println(originalMap) // 输出 map[a:100 b:2 c:3] fmt.Println(newMap) // 输出 map[a:1 b:2 c:3] ``` 2. 使用第三方库: - 可以使用一些第三方库来实现拷贝,例如`github.com/mitchellh/copystructure`库提供了`copystructure.Copy()`函数,可以用于拷贝map及其他复杂数据结构。 示例代码: ```go import ( "github.com/mitchellh/copystructure" ) originalMap := map[string]int{"a": 1, "b": 2, "c": 3} // 进拷贝 newMap, err := copystructure.Copy(originalMap) if err != nil { // 错误处理 } // 修改原始map的值 originalMap["a"] = 100 fmt.Println(originalMap) // 输出 map[a:100 b:2 c:3] fmt.Println(newMap) // 输出 map[a:1 b:2 c:3] ``` 无论是手动复制元素还是使用第三方库,都可以实现map拷贝操作。根据实际需求选择适合的方法。

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值