伍佰目录 短网址
  当前位置:海洋目录网 » 站长资讯 » 站长资讯 » 文章详细 订阅RssFeed

阿里面试题:说说HashMap的扩容过程?

来源:本站原创 浏览:66次 时间:2023-01-22

这是一道阿里的面试题,考察你对HashMap源码的了解情况,废话不多说,咱们就直接上源码吧!

jdk 1.7 源码
void resize(int newCapacity) {        Entry[] oldTable = table;//保存旧数组        int oldCapacity = oldTable.length;        if (oldCapacity == MAXIMUM_CAPACITY) {//判断当前数组大小是否达到最大值            threshold = Integer.MAX_VALUE;            return;        }        Entry[] newTable = new Entry[newCapacity];//创建一个新数组        boolean oldAltHashing = useAltHashing;        useAltHashing |= sun.misc.VM.isBooted() &&                (newCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);        boolean rehash = oldAltHashing ^ useAltHashing;//是否需要重新计算hash值        transfer(newTable, rehash);//将oldTable的元素迁移到newTable        table = newTable;//将新数组重新赋值              //重新计算阈值        threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);}void transfer(Entry[] newTable, boolean rehash) {        int newCapacity = newTable.length;        for (Entry<K,V> e : table) {//遍历oldTable迁移元素到newTable            while(null != e) {//①处会导致闭环,从而导致e永远不为空,然后死循环,内存直接爆了                Entry<K,V> next = e.next;                if (rehash) {//是否需要重新计算hash值                    e.hash = null == e.key ? 0 : hash(e.key);                }                int i = indexFor(e.hash, newCapacity);                e.next = newTable[i];//①                newTable[i] = e;//①                e = next;//①            }        }}
jdk 1.8 源码(比较长,慢慢品哈)
final Node<K,V>[] resize() {        Node<K,V>[] oldTab = table;//保存旧数组        int oldCap = (oldTab == null) ? 0 : oldTab.length;        int oldThr = threshold;//保存旧阈值        int newCap, newThr = 0;//创建新的数组大小、新的阈值        if (oldCap > 0) {            if (oldCap >= MAXIMUM_CAPACITY) {//判断当前数组大小是否达到最大值                threshold = Integer.MAX_VALUE;                return oldTab;            }            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&                     oldCap >= DEFAULT_INITIAL_CAPACITY)                newThr = oldThr << 1; //扩容两倍的阈值        }        else if (oldThr > 0) // 初始化新的数组大小            newCap = oldThr;        else {//上面条件都不满足,则使用默认值            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"})              //创建一个newCap大小的数组Node        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];        table = newTab;        if (oldTab != null) {            for (int j = 0; j < oldCap; ++j) {//遍历旧的数组                Node<K,V> e;                if ((e = oldTab[j]) != null) {                    oldTab[j] = null;//释放空间                    if (e.next == null)                      //如果旧数组中e后面没有元素,则直接计算新数组的位置存放                        newTab[e.hash & (newCap - 1)] = e;                    else if (e instanceof TreeNode)//如果是红黑树则单独处理                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);                    else { //链表结构逻辑,解决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;                        }                        //原索引+oldCap放入数组中                        if (hiTail != null) {                            hiTail.next = null;                            newTab[j + oldCap] = hiHead;//jdk1.8优化的点                        }                    }                }            }        }        return newTab;    }


总结

jdk1.7扩容是重新计算hash;jdk1.8是要看看原来的hash值新增的那个bit是1还是0好了,如果是0则索引没变,如果是1则索引变成"原索引+oldCap".这是jdk1.8的亮点,设计的确实非常的巧妙,即省去了重新计算hash值得时间,又均匀的把之前的冲突的节点分散到新的数组bucket上

jdk1.7在rehash的时候,旧链表迁移到新链表的时候,如果在新表的数组索引位置相同,则链表元素会倒置,但是jdk1.8不会倒置


  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net