0
点赞
收藏
分享

微信扫一扫

HashMap源码分析—resize方法

_刘彦辉 2022-05-01 阅读 22

resize

final Node<K,V>[] resize() {
    
    // oldTab引用扩容前的哈希表
    Node<K,V>[] oldTab = table;
    
    // 扩容前长度  如果扩容前hash表是null(刚刚初始化好) 那么就=0
    // 否则就是 扩容前hash表的长度
    int oldCap = (oldTab == null) ? 0 : oldTab.length;
    
    // 扩容前的 扩容阈值 
    int oldThr = threshold;
    
    // 新长度 新扩容阈值
    int newCap, newThr = 0;
    
    // 如果扩容前大小>0  表明这是已经初始化过的hashMap
    if (oldCap > 0) {
        // 如果扩容前容量已经≥了最大值
        if (oldCap >= MAXIMUM_CAPACITY) {
            // 给扩容阈值设置一个很大的数
            threshold = Integer.MAX_VALUE;
            // 直接返回 ,不能再扩容了
            return oldTab;
        }
        // 正常的扩容
        // 将扩容前大小左移一位 *2 赋给 新大小
        // 如果新大小<最大值  并且扩容前大小>16
        // 就把旧扩容阈值放大两倍
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                 oldCap >= DEFAULT_INITIAL_CAPACITY)
            // ?? 这里为什么要大于等于16 才左移  而小于16 时 要到最下面 计算
            newThr = oldThr << 1; // double threshold
    }
    
    // 没有初始化过的 hashMap
    // 并且oldThr>0  
    // 情况1 :new HashMap(initCap,loadFactor)  如果传入8 oldThr就是8 如果4 就是4
    // 如果传9 就是16
    // 情况2 :new HashMap(initCap)  和情况1一样
    // 情况3 :new HashMap(map) 并且map有数据
    else if (oldThr > 0) // initial capacity was placed in threshold
        // 把旧阈值赋给新大小
        // 如果是以上三种情况 那么旧阈值其实就是数组的大小
        // 又因为当前没有初始化 那么直接将旧阈值赋给新大小即可
        newCap = oldThr;
    // 没有初始化过 并且oldThr=0
    // 情况:没有赋初值的初始化
    else {               // zero initial threshold signifies using defaults
        // 新大小 直接为 16默认值
        newCap = DEFAULT_INITIAL_CAPACITY;
        // 新阈值为 16*0.75 = 12
        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }
    
    // 如果新阈值=0
    // 在上述几种情况中
    // 没有初始化过hashMap  并且在new HashMap时 有传入大小
    // 那么新的阈值就没有处理 而是0
    // 另外一种是:已经初始化过了  但是旧的容量没有超过16
    if (newThr == 0) {
        // 新阈值=新大小*0.75
        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];
    table = newTab;
    
    // 说明扩容前已经有数据了  而不是第一次创建数组
    if (oldTab != null) {
        // 循环处理旧数组中的每一个
        for (int j = 0; j < oldCap; ++j) {
            // 当前Node节点
            Node<K,V> e;
            // 如果当前节点不是null
            // 但是数据的具体是单个数据,还是链表,还是红黑树并不知道
            if ((e = oldTab[j]) != null) {
                // 首先将原来的设为null 方便垃圾回收
                oldTab[j] = null;
                // 如果e.next为空 说明这就是一个单独的元素 没有链表也没有树
                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
                    
                    // 低位链表  16—》32  索引15的哪个位置
                    Node<K,V> loHead = null, loTail = null;
                    // 高位链表  16—》32  索引31的哪个位置
                    Node<K,V> hiHead = null, hiTail = null;
                    Node<K,V> next;
                    
                    // 这个do-while循环相当于在原来的链表上做了一个拆分的工作
                    // 然后将拆分好的两个链表 赋给 低位和高位
                    // do while循环
                    // e 是 旧桶位第一个node
                    do {
                        next = e.next;
                        // 例子:16——》32
                        // 原来在15中的数据有两种
                        // .... 1 1111
                        // .... 0 1111 
                        // 那么& 10000
                        // 就只会出现 0 和 1 两种结果
                        // 如果是0 就放在低位
                        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;
                    }
                } // 如果是链表
                
            } // 如果不是空
        } // for
    }
    return newTab;
}
举报

相关推荐

0 条评论