HashMap深浅拷贝探究

1、先说结论

(1)HashMap的clone和new HashMap(Map<? extends K, ? extends V> m)均为深拷贝;

(2)直接使用=赋值为浅拷贝;

2、源码验证

  (1) new HashMap(Map<? extends K, ? extends V> m)

    public HashMap(Map<? extends K, ? extends V> m) {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        putMapEntries(m, false);
    }

从中可以看到其中调用了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); <==================
            }
        }
    }

在putMapEntries中可以看到调用了putVal方法

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null); <========新map中必然不存在此键,创建新的节点
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

新的HashMap中不存在此键,故会执行箭头处的语句,所以会创建新Node;

    Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) {
        return new Node<>(hash, key, value, next);
    }

在newNode中我们可以看到确实根据键值创建了一个新的Node,因此这也从源码层面证明了其为深拷贝;

(2) 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();
        result.putMapEntries(this, false); <=======================================
        return result;
    }

可以看到在clone方法中调用的也是putMapEntries方法,和new HashMap(Map<? extends K, ? extends V> m)中一样,故它也是深拷贝;

3、实验验证

public class HashMapTest {
    public static void main(String[] args) {
        HashMap<Character, Integer> map1 = new HashMap<Character, Integer>(){{
            put('a', 1);
            put('b', 2);
        }};

        HashMap<Character, Integer> map2 = new HashMap<>(map1);
        HashMap<Character, Integer> map3 =  (HashMap<Character, Integer>)map1.clone();

        map1.put('a', 999);
//        System.out.println(map1.put('a', 999));

        System.out.println(map1);
        System.out.println(map2);
        System.out.println(map3);
    }
}

在修改map1中a键对应的值为999后,输出map2,map3的值;

因此,从实验中也可以看到,HashMap的clone和new HashMap(Map<? extends K, ? extends V> m)为深拷贝。

展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读