put

  1. final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
  2. boolean evict) {
  3. Node<K,V>[] tab; Node<K,V> p; int n, i;
  4. if ((tab = table) == null || (n = tab.length) == 0)
  5. //查看Node数组是否为空或Node数组长度是否为0,
  6. //满足条件则进行首次扩容(初始化),默认长度为16,
  7. //并且设置阈值为12。判断是否第一次扩容,如果是则进行元素的移动,
  8. //反之直接返回初始化后的Node数组
  9. n = (tab = resize()).length;
  10. if ((p = tab[i = (n - 1) & hash]) == null)
  11. //Node数组长度-1&key的hash函数计算值获取下标位置。如果对应下标元素为null,则直接插入
  12. tab[i] = newNode(hash, key, value, null);
  13. else {
  14. Node<K,V> e; K k;
  15. if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
  16. //根据上一步的寻址找到对应Node对象,判断hash值是否一致,
  17. //或者key的equals一致则赋值给临时变量
  18. //考虑数据量不多的情况,链表的第一个Node就是寻址目标
  19. e = p;
  20. else if (p instanceof TreeNode)
  21. //如果是树形结构,那么强转为TreeNode进行put操作
  22. e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
  23. else {
  24. for (int binCount = 0; ; ++binCount) {
  25. if ((e = p.next) == null) {
  26. //寻址到的Node的后一个兄弟节点为null,加入到链表中
  27. p.next = newNode(hash, key, value, null);
  28. if (binCount >= 8 - 1) // -1 for 1st
  29. //挂载Node大于等于7则进行红黑树转换,跳出循环
  30. treeifyBin(tab, hash);
  31. break;
  32. }
  33. if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
  34. //寻址到了Node,经过equals方法确认是当前Node,跳出循环
  35. break;
  36. //赋值,为下一次判断
  37. p = e;
  38. }
  39. }
  40. if (e != null) { // existing mapping for key
  41. //对寻址到的Node进行操作,线取出旧的值
  42. V oldValue = e.value;
  43. //如果存在就不进行赋值操作,此处onlyIfAbsent为false,所以恒真,会将值覆盖
  44. if (!onlyIfAbsent || oldValue == null)
  45. e.value = value;
  46. afterNodeAccess(e);
  47. return oldValue;
  48. }
  49. }
  50. //统一处理 修改次数累加,对下次put预扩容
  51. ++modCount;
  52. if (++size > threshold)
  53. resize();
  54. afterNodeInsertion(evict);
  55. return null;
  56. }

resize_

final Node<K,V>[] resize() {
        Node<K,V>[] oldTab = table;
        int oldCap = (oldTab == null) ? 0 : oldTab.length;//当前Node数组长度
        int oldThr = threshold;//当前长度阈值
        int newCap, newThr = 0;
        if (oldCap > 0) {
            if (oldCap >= MAXIMUM_CAPACITY) {
                //如果容量已经大于等于2的31次方,那么阈值等于int最大值
                threshold = Integer.MAX_VALUE;
                return oldTab;
            }
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY)
                //如果新容量小于2的31次方并且旧容量大于等于默认容量,那么新阈值等于旧阈值*2
                newThr = oldThr << 1; // double threshold
        }
        else if (oldThr > 0) // initial capacity was placed in threshold
            newCap = oldThr;
        else {               // zero initial threshold signifies using defaults
            //默认容量,默认阈值
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        if (newThr == 0) {
            float ft = (float)newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);
        }
        //赋值新阈值
        threshold = newThr;
        @SuppressWarnings({"rawtypes","unchecked"})
        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
        //赋值Node数组
        table = newTab;
        if (oldTab != null) {
            //非初始化操作,进行元素的移动
            for (int j = 0; j < oldCap; ++j) {
                Node<K,V> e;
                if ((e = oldTab[j]) != null) {
                    oldTab[j] = null;
                    if (e.next == null)
                        newTab[e.hash & (newCap - 1)] = e;
                    else if (e instanceof TreeNode)
                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                    else { // preserve order
                        Node<K,V> loHead = null, loTail = null;
                        Node<K,V> hiHead = null, hiTail = null;
                        Node<K,V> next;
                        do {
                            next = e.next;
                            if ((e.hash & oldCap) == 0) {
                                if (loTail == null)
                                    loHead = e;
                                else
                                    loTail.next = e;
                                loTail = e;
                            }
                            else {
                                if (hiTail == null)
                                    hiHead = e;
                                else
                                    hiTail.next = e;
                                hiTail = e;
                            }
                        } while ((e = next) != null);
                        if (loTail != null) {
                            loTail.next = null;
                            newTab[j] = loHead;
                        }
                        if (hiTail != null) {
                            hiTail.next = null;
                            newTab[j + oldCap] = hiHead;
                        }
                    }
                }
            }
        }
        return newTab;
    }

remove

final Node<K,V> removeNode(int hash, Object key, Object value,
                               boolean matchValue, boolean movable) {
        Node<K,V>[] tab; Node<K,V> p; int n, index;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (p = tab[index = (n - 1) & hash]) != null) {
            //判断Node数组是否初始化过并且是否长度不为0并且能够寻址到对应下标不为null
            Node<K,V> node = null, e; K k; V v;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                //如果第一个就是要移除的元素,通过hash和equals判断
                node = p;
            else if ((e = p.next) != null) {
                if (p instanceof TreeNode)
                    //如果是树形结构,通过树的方法寻找元素
                    node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
                else {
                    //挂载了N个节点,hash+equals寻找
                    do {
                        if (e.hash == hash &&
                            ((k = e.key) == key ||
                             (key != null && key.equals(k)))) {
                            node = e;
                            break;
                        }
                        p = e;
                    } while ((e = e.next) != null);
                }
            }
            //移除元素,但是可能考虑缩容后要重新开辟空间,并且原有的内存需要GC回收而引发STW,所以没做处理
            if (node != null && (!matchValue || (v = node.value) == value ||
                                 (value != null && value.equals(v)))) {
                if (node instanceof TreeNode)
                    ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
                else if (node == p)
                    tab[index] = node.next;
                else
                    p.next = node.next;
                ++modCount;
                --size;
                afterNodeRemoval(node);
                return node;
            }
        }
        return null;
    }

get

final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            //需要Node数组初始化过
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                //第一个就满足,则直接返回
                return first;
            if ((e = first.next) != null) {
                //解决hash碰撞问题,equals确认唯一实例
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

总结

增删改查操作都是基于hash寻址,然后通过equals解决hash碰撞问题。另在寻址期间优先考虑第一个,因为散列大多情况下发生碰撞的几率不高。在扩容时,每次增加一倍,具体操作为向左位移1位,为2的N次幂,主要解决元素移动次数。另不会在移除后缩容,考虑STW带来的效率问题,在链表转红黑树时,也会判断Node数组长度是否大于64,如果小于该容量,也会进行扩容操作