HashMap core source code analysis (jdk8)

write in front

If you are not clear about the basic working principle of HashMap, the effect of continuing to read the subsequent content is not very good. It is recommended to learn the basic working principle of HashMap beforehand:  https://my.oschina.net/j4love/blog/1797058

 

java.util.HashMap # 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;

        // table 为 null 说明是首次调用 put 方法 , 进行 resize 操作真正为 table 分配存储空间

        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;

        // i = (n - 1) & hash 计算出的值判断 table[i] 是否为 null , 
        // 如果为 null 就为 key , value 创建一个新的 Node 节点 ,
        // 不需要进行碰撞检测直接存储在 table 中 i 的位置上 

        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;

            // 检测要存储的 key 是否和 bucket 中存储的头节点相同
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;

            // 检测 bucket 中当前存放的节点类型是不是红黑树结构 ,
            // 是红黑树结构 , 存储为一个红黑树节点

            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {

                // 这个 bucket 中存放的节点是链表结构 , 
                // 循环直到链表的末尾或者是找到相同的 key 

                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);

                        // 存储新节点的时候 , 检测链表长度是否超过 TREEIFY_THRESHOLD - 1 ,
                        // 超过的话将链表转换为红黑树结构 ,提高性能

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

        // 并发修改计数器 ,有并发修改就抛异常 ConcurrentModificationException
        ++modCount;

        // 存储了一个新节点 , 检测 size 是否超过 threshold 
        // 如果超过了要进行 resize 操作
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

 

java.util.HashMap#getNode

    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;

        // 检测 table 中是否已经存储了节点 ,
        // 检测key所在的 bucket 是否存储了节点 ,
        // 以上两点都不满足说明 key 不存在

        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {

            // 对 bucket 中存储节点的头结点进行碰撞检测 ,
            // 如果运气好的话只需要进行这一次碰撞检测

            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;

            // 检测 bucket 存储的节点是否是单个节点

            if ((e = first.next) != null) {

                // 检测节点数据结构是否是红黑树

                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {

                    // 节点是链表数据结构,循环直到链表末尾或者是发现 key 一致的节点
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

 

java.util.HashMap#removeNode

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<K,V> node = null, e; K k; V v;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                node = p;
            else if ((e = p.next) != null) {
                if (p instanceof TreeNode)
                    node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
                else {
                    do {
                        if (e.hash == hash &&
                            ((k = e.key) == key ||
                             (key != null && key.equals(k)))) {
                            node = e;
                            break;
                        }
                    
                        // p 是 node 的前一个节点
                        p = e;
                    } while ((e = e.next) != null);
                }
            }

            // 以上代码是 getNode(hash , key) , 个人觉得这个函数中的代码冗余了

            // 获取到 key 对应的节点 , 判断是否要进行值匹配

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

 

java.util.HashMap#clear

    public void clear() {
        Node<K,V>[] tab;
        modCount++;
        if ((tab = table) != null && size > 0) {
            size = 0;

            // 很简单把数组中每个位置设置为 null
            for (int i = 0; i < tab.length; ++i)
                tab[i] = null;
        }
    }

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325266333&siteId=291194637