关于HashMap的相关问题

关于HashMap的相关问题

  1. 如果HashMap的大小超过了负载因子定义的容量,将会怎么进行扩容?

    ​ 默认的负载因子大小为0.75,也就是说,当一个hashMap填充到75%的时候,将会创建一个是原来大小的点二倍的bucket数组,用来调整HashMap的大小,将原来的对象放入到新的bucket数组当中(在这个过程中,原来在bucket[i]中的元素,进过hash,可能会改变这个位置,变为bucket[原来数组长+i])。

  2. 为什么负载因子是0.75,而不是其他数据呢?

    ​ 首先如果加载因子比较大,那么扩容发生的频率就比较低,但是他浪费的空间比较小,不过发生hash冲突的几率就比较大,比如加载因子是1的时候,如果hashmap长度为128,那么可能hashmap的实际存储元素数量在64至128之间的时间段比较多,而这个时间段发生hash冲突就比较大,造成数组中其中一条链表较长,就会影响性能。

    ​ 当加载因子值比较小的时候,扩容的频率就会变高,因此会占用更多的空间,但是元素的存储就比较稀疏,发生哈希冲突的可能性就比较小,因此操作性能会比较高,比如设置成0.5,同样128长度的hashmap,当数量达到65的时候就会触发hashmap的扩容,扩容后长度为256,256里面只存储了65个似乎有点浪费了。

  3. HashMap中关于链表转化为红黑树

    ​ 树化源码如下:

        final void treeifyBin(Node<K,V>[] tab, int hash) {
            int n, index; Node<K,V> e;
            if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
                resize();
            else if ((e = tab[index = (n - 1) & hash]) != null) {
                TreeNode<K,V> hd = null, tl = null;
                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);
                if ((tab[index] = hd) != null)
                    hd.treeify(tab);
            }
        }
    

    在这里插入图片描述

    有if - else可知,当数组长度小于MIN_TREEIFY_CAPACITY(64)的时候,会进行扩容,但不会将链表转换为红黑树,即使链表中的元素超过了8个

  4. JDK1.8 HashMap 扩容是做了哪些优化?

    ​ 在JDK 1.7 中HashMap是以数组加链表的形式组成的,而在JDK 1.8之后,新增了红黑树的组成接口。当链表长度大于8并且数组容量大于64的时候,链表将装换为红黑树。即使在hashcode完全相同的极端情况下,由于红黑树的性质,查找摸个特定元素也只需要O(log n)的时间复杂度,而链表则需要O(n),从而大大提高了检索的效率。

  5. HashMap 是如何导致死循环的?

    ​ 死循环都是说JDK1.7的HashMap 的死循环,主要是在多线程情况下,多个线程对map进行扩容的同时曹成的,jdk7扩容关键代码如图所示:

    在这里插入图片描述

    ​ 造成死循环的原因:

    在这里插入图片描述

    ​ 造成死循环的原因主要在于线程1执行单key=9,并取出他的next(key=25)作为下次遍历后,线程1交出了执行权休息去了,而接着线程2吭哧吭哧的执行完扩容,扩容由于采用头插法,此时key=25那个Entry对象的next是key=9。

    ​ 所以当线程1继续执行,到遍历next(key=25)时他的next变成了key=9,最终造成了两个Entry互相引用,如果后面调用map.get(41)就会刚好查询table[9],然后遍历这个链表,造成死循环!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王野也不野

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值