美文网首页
HashMap注释版

HashMap注释版

作者: 河神 | 来源:发表于2020-04-12 22:28 被阅读0次

    哈 ,一年一更新 ,orz

    鉴于jdk里面源码实在是贼乱,代码倒是不难,但是写的太紧凑了(
    你为毛不加括号,为毛啊,看起来费劲
    ),我决定刨开写写注释


    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是否为空,为空则进行  resize() 操作,
            if ((tab = table) == null || (n = tab.length) == 0){
                n = (tab = resize()).length;
            }
            //此时: n =  table的容量  
            //      tab = table表
    
            // 计算hash对应table的数组下标 
            i = (n - 1) & hash;
            //取出对应位置的节点
            p = tab[i];
            //如果对应节点为空的话,就创建一个新的节点
            if ( p  == null){
                tab[i] = newNode(hash, key, value, null);
            } else {
            //如果节点不为空的话
                Node<K,V> e;
                K k;
                //当前取到的节点的hash值和请求的的hash相等 并且
                //key值也和请求的key内存位置相等 或者  equals相等 总之 ,如果判断是一个对象 
                if (p.hash == hash &&
                      (
                          (k = p.key) == key ||   (key != null && key.equals(k))
                      )
                    ){
                    //直接将当前节点赋给e
                    e = p;
                }else if (p instanceof TreeNode){
                    //如果当前节点是一个树节点,就使用 putTreeVal 的方式进行插入
                    //并且,如果 key 如果判断是一个对象  就返回, 如果插入成功,就返回null
                    e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
                }else {
                    //如果当前是链表节点,便利链表节点
                    for (int binCount = 0; ; ++binCount) {
                        //如果当前节点下一个节点是null,就添加一个新节点放在 p 后面
                        if ((e = p.next) == null) {
                            p.next = newNode(hash, key, value, null);
    
                            //如果这个时候,达到了树 阈值 ,就 执行treeifyBin
                            //但是 实际上,如果没有达到 MIN_TREEIFY_CAPACITY = 64 最小容量,也是不会转化为树的,只是执行 resize 操作
                            //这个很多人以为 到8就转化为树 ,其实是不对的
                            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;
                    }
                }
    
                //所以这里只有 如果判断是一个对象  就是说 existing mapping for key 的时候才会调用
                if (e != null) { // existing mapping for key
                    V oldValue = e.value;
                    //value 替换为最新的
                    if (!onlyIfAbsent || oldValue == null){
                        e.value = value;
                    }
                    afterNodeAccess(e);
                    return oldValue;
                }
            }
            //修改次数,修改版本+1
            ++modCount;
            //不够用了,resize
            if (++size > threshold){
                resize();
            }
            //LinkHashMap用的
            afterNodeInsertion(evict);
            return null;
        }
    

    treeifyBin方法 将一个hash对应节点位置的 链表转化为红黑树

        
        final void treeifyBin(Node<K,V>[] tab, int hash) {
            int n, 
            index; 
            Node<K,V> e;
     
            //划重点,不是到8就转化为树,而是大于 MIN_TREEIFY_CAPACITY = 64 的时候才会去转化 ,否则就是 resize
            if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY){
                resize();
    
                //大于 64 ,并且table 的 hash 计算 的位置的节点不为空 ,判断很严谨啊
                //e,此时为 hash对应位置 首个节点 
            }else if ((e = tab[index = (n - 1) & hash]) != null) {
    
                TreeNode<K,V> hd = null,
                tl = null;
                //do循环整起来,
                do {
                    //构造一个树节点,没啥
                    TreeNode<K,V> p = replacementTreeNode(e, null);
    
    
                    if (tl == null)
                        hd = p;
                    else {
                        p.prev = tl;
                        tl.next = p;
                    }
                    tl = p;
                } while ((e = e.next) != null);
    
                //总之经过上面,hd 变成了一个 链表 ,一个节点上 TreeNode 的链表
                //所以下一步自然是要把链表转化成树
                if ((tab[index] = hd) != null){
                    //向下看
                    hd.treeify(tab);
                }
            }
        }
    

    treeify 方法 把链表转化为🌲 --- 未完待续

    
    
            /**
             * Forms tree of the nodes linked from this node.
             */
            final void treeify(Node<K,V>[] tab) {
                
                //红黑树的根节点
                TreeNode<K,V> root = null;
    
                //国际惯例,先便利链表
                //初始化的时候 x 就是head节点 ,
                //之后依次往后
                for (TreeNode<K,V> x = this, next; x != null; x = next) {
                    
                    //next 当前节点下一个节点
                    next = (TreeNode<K,V>)x.next;
                    //当前节点左右子树🍠设置为null
                    x.left = x.right = null;
    
                    //初始化根节点
                    if (root == null) {
                        x.parent = null;
                        x.red = false;
                        root = x;
                    }else {
                        K k = x.key;
                        int h = x.hash;
                        Class<?> kc = null;
                        //开始决定当前节点插入到那个 下面,
                        for (TreeNode<K,V> p = root;;) {
                            int dir,
                            ph;
                            K pk = p.key;
    
                            //----决定dir的大小
                            if ((ph = p.hash) > h){
                                dir = -1;
                            }else if (ph < h){
                                dir = 1;
                            }else if ((kc == null &&
                                      (kc = comparableClassFor(k)) == null) ||
                                     (dir = compareComparables(kc, k, pk)) == 0){
                                dir = tieBreakOrder(k, pk);
                            }
                            //----
                                
    
                            TreeNode<K,V> xp = p;
                            //如果 dir小于0 也就是 当前这个比当前值小的,就把左子树 设置为p 
                            //所以看到了吧 hashMap的红黑树 大顶树
                            if ((p = (dir <= 0) ? p.left : p.right) == null) {
                                x.parent = xp;
                                
                                if (dir <= 0){
                                    xp.left = x;
                                }else{
                                    xp.right = x;
                                }
    
                                root = balanceInsertion(root, x);
                                break;
                            }
                        }
                    }
                }
                moveRootToFront(tab, root);
            }    
    

    相关文章

      网友评论

          本文标题:HashMap注释版

          本文链接:https://www.haomeiwen.com/subject/grkimhtx.html