When Map to copy the new Map, with "=, clone, or putAll"? On the deep and shallow copy copy of Map

scenes to be used

When we first use the map to copy the code to develop business, often stepped shades copy (copies) of this pit, like me, in the Map replication
(eg: Map <String, String> new_Map = old_Map) appeared the following two types of problems :

1. Map <String, String> new_Map = old_Map operation, when the modified new_map properties, old_Map property also followed changed, but I have not changed old_Map ;
2. Since the value of the Map value not only the basic data types, further there are reference data types, so when I modify a reference type attribute, new_Map and old_Map reference variable values change ; (if you are the basic types of value, the problem does not involve shades of copies)

Tried approach

1. "=" assignment

Create a Map, and then use the "=" direct assignment, so just copy the old_Map references, and old_Map still use the same memory area, therefore, in modifications new_Map when the value old_Map also vary.

<Map<String, String> new_Map = old_Map>

The above approach does not work, use Map itself provided most of the Internet, said putAll () and clone () method is a deep copy, but the actual use found objects around the Map references or have been changed; this is the beginning Speaking , these two methods only modify the basic data types, if the reference type is not, these two methods are shallow copy!

Come, let us look together with the source ↓↓↓

2. .putAll () method

Map create a new structure, putAll () method to add to the original Map New Map, but found after making changes to Map a copy of the original data Map has also been modified; (source below)

	public void putAll(Map<? extends K, ? extends V> m) {
        putMapEntries(m, true); // 调用了putMapEntries方法
    }
	
	final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
        int s = m.size();
        if (s > 0) {
            if (table == null) { // pre-size
                float ft = ((float)s / loadFactor) + 1.0F;
                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                         (int)ft : MAXIMUM_CAPACITY);
                if (t > threshold)
                    threshold = tableSizeFor(t);
            }
            else if (s > threshold)
                resize();
            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
                K key = e.getKey();
                V value = e.getValue();
                putVal(hash(key), key, value, false, evict); // 循环调用了value,但value中的引用对象指针并没有改变。
                // 扩展:map.put("key","value")的put()也是调用了putVal()方法
            }
        }
    }

3. Use .clone () method

HashMap comes a clone () method, but it describes the annotated source is only a shallow copy (copies) as follows :( source)

	@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<? extends K, ? extends V> m, boolean evict) {
        int s = m.size();
        if (s > 0) {
            if (table == null) { // pre-size
                float ft = ((float)s / loadFactor) + 1.0F;
                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
                         (int)ft : MAXIMUM_CAPACITY);
                if (t > threshold)
                    threshold = tableSizeFor(t);
            }
            else if (s > threshold)
                resize();
            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
                K key = e.getKey();
                V value = e.getValue();
                putVal(hash(key), key, value, false, evict); // 同上,循环调用了“value”,value中的引用对象指针并没有改变
            }
        }
    }

Test Case

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]}

# The top two raw data, using a method of copying a putAll new_map new object
# middle of the two, is substantially modified old_map object data types, and did not affect the new_map object.
# But look at the second group of the countdown, change the reference data types, they found value new_map also changed, so putAll did not have a deep copy of old_map.
# Final surface is in serialized fashion, was found to change the type of data when the reference, new_map the object has not changed, there arises a deep copy. (Clone methods below provide custom source)
# tools described above, the object may be achieved deep copy, the HashMap is not limited, provided that implements Serlizeable interface.

Test case source

package com.softsec.demo;

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

public class demoMap implements Cloneable{

    public static void main(String[] srag) {
        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);
        list.add(400);
        System.out.println("old:" + old_map);
        System.out.println("new:" + new_map);
    }

    /**
     * 自定义clone方法(对象必须是实现了Serializable接口)
     *
     */
    public static <T extends Serializable> 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;
    }


}

Published 52 original articles · won praise 122 · views 30000 +

Guess you like

Origin blog.csdn.net/qq_39390545/article/details/102717884