从HashMap的常用方法来解析HashMap的内部实现(2)

上篇文章(http://www.jianshu.com/p/a122c79ee60c
我们分析了HashMap的构造和put方法,这篇文章来看看它的其他方法

putAll
  @Override 
  public void putAll(Map<? extends K, ? extends V> map) {
        ensureCapacity(map.size());
        super.putAll(map);
  }

我们来看看 ensureCapacity(map.size());方法

  private void ensureCapacity(int numMappings) {
        int newCapacity = Collections.roundUpToPowerOfTwo(capacityForInitSize(numMappings));
        HashMapEntry<K, V>[] oldTable = table;
        int oldCapacity = oldTable.length;
        if (newCapacity <= oldCapacity) {
            return;
        }
        if (newCapacity == oldCapacity * 2) {
            doubleCapacity();
            return;
        }

        // We're growing by at least 4x, rehash in the obvious way
        HashMapEntry<K, V>[] newTable = makeTable(newCapacity);
        if (size != 0) {
            int newMask = newCapacity - 1;
            for (int i = 0; i < oldCapacity; i++) {
                for (HashMapEntry<K, V> e = oldTable[i]; e != null;) {
                    HashMapEntry<K, V> oldNext = e.next;
                    int newIndex = e.hash & newMask;
                    HashMapEntry<K, V> newNext = newTable[newIndex];
                    newTable[newIndex] = e;
                    e.next = newNext;
                    e = oldNext;
                }
            }
        }
    }

首先得到一个新的容量newCapacity,如果等于旧容量的2倍就调用doubleCapacity()方法,这个方法在上一篇已经解析过了,这边就不再说了,makeTable方法创建一个新的数组,上篇文章也解析过了,下面着重看看这个循环

    if (size != 0) {
            int newMask = newCapacity - 1;
            for (int i = 0; i < oldCapacity; i++) {
                for (HashMapEntry<K, V> e = oldTable[i]; e != null;) {
                    HashMapEntry<K, V> oldNext = e.next;
                    int newIndex = e.hash & newMask;
                    HashMapEntry<K, V> newNext = newTable[newIndex];
                    newTable[newIndex] = e;
                    e.next = newNext;
                    e = oldNext;
                }
            }
        }

首先计算出数据在新的数组当中的index下标,如果next有数据又改变了链表的顺利,总之就是把旧数组当中的数据添加到了新的数组当中,然后调用父类的putAll方法

public void putAll(Map<? extends K, ? extends V> map) {
        for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
            put(entry.getKey(), entry.getValue());
        }
}

首先遍历map对象参数,然后调用HashMap的put方法添加数据。

get方法

  public V get(Object key) {
        if (key == null) {
            HashMapEntry<K, V> e = entryForNullKey;
            return e == null ? null : e.value;
        }

        int hash = Collections.secondaryHash(key);
        HashMapEntry<K, V>[] tab = table;
        for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)];
                e != null; e = e.next) {
            K eKey = e.key;
            if (eKey == key || (e.hash == hash && key.equals(eKey))) {
                return e.value;
            }
        }
        return null;
    }

如果key==null,就返回entryForNullKey对象,不为null,首先计算hash值,然后计算index下标,得到对象
如果eKey == key || (e.hash == hash && key.equals(eKey)) 条件成立,就返回value。

remove方法

  @Override 
  public V remove(Object key) {
        if (key == null) {
            return removeNullKey();
        }
        int hash = Collections.secondaryHash(key);
        HashMapEntry<K, V>[] tab = table;
        int index = hash & (tab.length - 1);
        for (HashMapEntry<K, V> e = tab[index], prev = null;
                e != null; prev = e, e = e.next) {
            if (e.hash == hash && key.equals(e.key)) {
                if (prev == null) {
                    tab[index] = e.next;
                } else {
                    prev.next = e.next;
                }
                modCount++;
                size--;
                postRemove(e);
                return e.value;
            }
        }
        return null;
    }

如果key为null,调用removeNullKey方法

  private V removeNullKey() {
        HashMapEntry<K, V> e = entryForNullKey;
        if (e == null) {
            return null;
        }
        entryForNullKey = null;
        modCount++;
        size--;
        postRemove(e);
        return e.value;
    }

设置entryForNullKey对象为null。

key不为空

 int hash = Collections.secondaryHash(key);
 HashMapEntry<K, V>[] tab = table;
 int index = hash & (tab.length - 1);
 for (HashMapEntry<K, V> e = tab[index], prev = null;
           e != null; prev = e, e = e.next) {
        if (e.hash == hash && key.equals(e.key)) {
             if (prev == null) {
                 tab[index] = e.next;
              } else {
                prev.next = e.next;
           }
           modCount++;
           size--;
           postRemove(e);
           return e.value;
        }
   }

首先得到index,然后循环
如果删除的数据在index位置,就把index位置的对象的下一个对象赋值给数组的index位置。
如果删除的数据在index位置的链表中间就把链表中间的这个数据删除掉,然后把中间数据的头和尾连接在一起。

结束语

到此HashMap的常用方法都分析完了,通过看源码对HashMap有了更深的理解。

    原文作者:伪文艺大叔
    原文地址: https://www.jianshu.com/p/336b1b45d140
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞