zoukankan      html  css  js  c++  java
  • 当旧数组不为空,扩容时候

    当旧数组不为空,扩容时候

          这里以 16 -> 32 开始讲解resize()方法 , 可见下方代码的具体注释.

    1 . 这是扩容的方法

    final Node<K,V>[] resize() {
            // 此时 Node[] table 应该是一个16位的数组, 将其赋值给oldTab.
            Node<K,V>[] oldTab = table;    


            // int oldCap = 16         
            int oldCap = (oldTab == null) ? 0 : oldTab.length;


            // threshold table内元素此时应该达到了临界值 , 16*0.75 = 12  , int oldThr = 12
            int oldThr = threshold;


            // 初始化新数组长度=0 , 临界值 = 0
            int newCap, newThr = 0;


            // 如果旧数组长度 >0
            if (oldCap > 0) {
                //  如果旧数组长度大于=最大值
                if (oldCap >= MAXIMUM_CAPACITY) {
                    // 将临界值设置为 Integer.MAX_VALUE , 数组的长度没办法扩容了, 新加的元素只能都加在上链表了
                    threshold = Integer.MAX_VALUE;
                    // 将旧数组返回 ,放弃扩容
                    return oldTab;
                }
                // 否则直接将旧数组的长度 向左移一位(oldCap*2), 如果扩容后,新数组长度 小于数组最大值. 这里其实也说明了数组每次扩容增大一倍
                else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                         oldCap >= DEFAULT_INITIAL_CAPACITY)
                         // 直接将数组扩容的临界值, 也直接 *2 .
                    newThr = oldThr << 1; // double threshold
            }


            else if (oldThr > 0)
                newCap = oldThr;


            else {              
                newCap = DEFAULT_INITIAL_CAPACITY;
                newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
            }


            // 如果新数组的临界值 == 0 .
            if (newThr == 0) {
                float ft = (float)newCap * loadFactor;
                newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                          (int)ft : Integer.MAX_VALUE);
            }


            // 将新数组的临界值赋值给成员变量 threshold
            threshold = newThr;
            @SuppressWarnings({"rawtypes","unchecked"})
                 //  这里创建一个新的数组, 长度为 newCap = 32
                Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
                // 同时将新数组赋值给成员变量table
            table = newTab;


            // 开始要将旧数组的元素往新数组上挪了
            // 如果旧数组不为 null
            if (oldTab != null) {
            //开始for循环就数组
                for (int j = 0; j < oldCap; ++j) {
                    Node<K,V> e;
                    // 将各个位置的头结点Node节点赋值给 e .
                    if ((e = oldTab[j]) != null) {
                        //将当前位桶的头结点赋值为null.
                        oldTab[j] = null;


                        // 如果头结点的下一个节点 ==null .也就是这个链表长度==1
                        if (e.next == null)
                            // 直接将这个元素放在新数组的,通过hash值与新数组的最大索引求 & ,同样保证索引必落在数组内.
                            newTab[e.hash & (newCap - 1)] = e;
                        else if (e instanceof TreeNode)
                             // 如果是树结构, 采用红黑树方式去挪元素
                            ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                        else {
                             // 不是红黑树,单链表的长度 != 1 , 开始采用高低位链进行扩容
                             // low 和 high


                            Node<K,V> loHead = null, loTail = null;   
                            Node<K,V> hiHead = null, hiTail = null;
                            Node<K,V> next;


                            // do while循环, do内代码必执行1次
                            // 只有当链表的下一个节点Node不为Null的时候,才会继续执行循环


                            do {
                                // 获取头结点的下一个节点 赋值给next , 现在e还是头结点
                                next = e.next;


                                // 如果 (头结点的hash & 旧的数组长度) == 0. 这个元素放在低位链表上
                                if ((e.hash & oldCap) == 0) {
                                    if (loTail == null)


                                     // 这是低位链表的头结点
                                        loHead = e;
                                    else


                                    // 低位链表的Node,通过Next关联起来.
                                        loTail.next = e;
                                    loTail = e;
                                }
                                else {
                                    // 否则就是高位链表. 也是通过next 进行关联.
                                    if (hiTail == null)
                                        hiHead = e;
                                    else
                                        hiTail.next = e;
                                    hiTail = e;
                                }
                            } while ((e = next) != null);
                            
                            
                            // 到达这里,说明原数组j位桶上的链表已经成功分为了低位链和高位链
                            
                            if (loTail != null) {
                                // 低位链表安装在新数组上, 还是在j位桶上.
                                loTail.next = null;
                                newTab[j] = loHead;
                            }
                            if (hiTail != null) {
                                // 高位链安装在新数组上. 索引 = j + oldCap(旧数组的长度)
                                hiTail.next = null;
                                newTab[j + oldCap] = hiHead;
                            }
                        }
                    }
                }
            }
            return newTab;
        }

    2 . 红黑树不说明,但是可以看一个知识点.

     a . 红黑树的扩容中. 如果链表目前长度小于 成员变量 6 . 会修改为链表格式

    人总得做点什么 ,不是么
  • 相关阅读:
    js 对象数组 排序
    sql 时间条件查询
    idea和Pycharm 等系列产品激活激活方法和激活码 100 年
    开源协议简介
    面试题
    VIM|基础命令
    git|基础命令
    VIM|复制
    lua|基础教程
    Printf格式输出详解
  • 原文地址:https://www.cnblogs.com/liweibing/p/12868033.html
Copyright © 2011-2022 走看看