jdk1.8 HashMap源码分析(resize函数)

来源:互联网 发布:linux更改jdk环境变量 编辑:程序博客网 时间:2024/05/15 11:09
final Node<K,V>[] resize() {        Node<K,V>[] oldTab = table;        int oldCap = (oldTab == null) ? 0 : oldTab.length;        int oldThr = threshold;        int newCap, newThr = 0;        //如果有容量,说明该map已经有元素        if (oldCap > 0) {             if (oldCap >= MAXIMUM_CAPACITY) {                threshold = Integer.MAX_VALUE;                return oldTab;            }            //在此处newCap = oldCap << 1,容量翻倍了            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&                     oldCap >= DEFAULT_INITIAL_CAPACITY)                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];        table = newTab;        /*            上面一顿操作,最后总结就是:            如果是最开始还没有元素的情况:                1、如果初始化的时候带了参数                    (HashMap(int initialCapacity, float loadFactor)),                    那么newCap就是你的initialCapacity参数                    threshold就是 (int)(initialCapacity*loadFactor)                2、否则就按默认的算 initialCapacity = 16,threshold = 12            如果已经有元素了,那么直接扩容2倍,如果            oldCap >= DEFAULT_INITIAL_CAPACITY了,那么threshold也扩大两倍        */        if (oldTab != null) {            //将原来map中非null的元素rehash之后再放到newTab里面去            for (int j = 0; j < oldCap; ++j) {                Node<K,V> e;                if ((e = oldTab[j]) != null) {                    oldTab[j] = null;                    //如果这个oldTab[j]就一个元素,那么就直接放到newTab里面                    if (e.next == null)                         newTab[e.hash & (newCap - 1)] = e;                    else if (e instanceof TreeNode)                        //如果原来这个节点已经转化为红黑树了,                        //那么我们去将树上的节点rehash之后根据hash值放到新地方                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);                    else { // preserve order                        /*                            这里的操作就是 (e.hash & oldCap) == 0 这一句,                            这一句如果是true,表明(e.hash & (newCap - 1))还会和                            e.hash & (oldCap - 1)一样。因为oldCap和newCap是2的次幂,                            并且newCap是oldCap的两倍,就相当于oldCap的唯一                            一个二进制的1向高位移动了一位                            (e.hash & oldCap) == 0就代表了(e.hash & (newCap - 1))还会和                            e.hash & (oldCap - 1)一样。                            比如原来容量是16,那么就相当于e.hash & 0x1111                             (0x1111就是oldCap - 1 = 16 - 1 = 15),                            现在容量扩大了一倍,就是32,那么rehash定位就等于                            e.hash & 0x11111 (0x11111就是newCap - 1 = 32 - 1 = 31)                            现在(e.hash & oldCap) == 0就表明了                            e.hash & 0x10000 == 0,这样的话,不就是                            已知: e.hash &  0x1111 = hash定位值Value                             并且  e.hash & 0x10000 = 0                            那么   e.hash & 0x11111 不也就是                            原来的hash定位值Value吗?                            那么就只需要根据这一个二进制位就可以判断下次hash定位在                            哪里了。将hash冲突的元素连在两条链表上放在相应的位置                            不就行了嘛。                        */                        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;    }
原创粉丝点击