HashMap的一些底层知识点

HashMap的底层数据结构?

数字+链表+红黑树

HashMap的存取原理?

①.判断键值对数组table[i]是否为空或为null,否则执行resize()进行扩容;

②.根据键值key计算hash值得到插入的数组索引i,如果table[i]==null,直接新建节点添加,转向⑥,如果table[i]不为空,转向③;

③.判断table[i]的首个元素是否和key一样,如果相同直接覆盖value,否则转向④,这里的相同指的是hashCode以及equals;

④.判断table[i] 是否为treeNode,即table[i] 是否是红黑树,如果是红黑树,则直接在树中插入键值对,否则转向⑤;

⑤.遍历table[i],判断链表长度是否大于8,大于8的话把链表转换为红黑树,在红黑树中执行插入操作,否则进行链表的插入操作;遍历过程中若发现key已经存在直接覆盖value即可;

⑥.插入成功后,判断实际存在的键值对数量size是否超多了最大容量threshold,如果超过,进行扩容。

为啥会线程不安全?

1.7中在并发的多线程使用场景中使用HashMap可能造成死循环。1.8中put/get方法都没有加同步锁,多线程情况最容易出现的就是:无法保证上一秒put的值,下一秒get的时候还是原值,所以线程安全还是无法保证。

默认初始化大小是多少?为啥是这么多?为啥大小都是2的幂?

初始化大小是16,当计算hash时最后会有一个取模运算(n - 1) & hash,n是数组长度,n必须每次都乘二才会有这个效果

HashMap的扩容方式?负载因子是多少?为什是这么多?

1.7中:首先会创建一个新的entry数组,大小为原来的两倍,然后将重新对旧数组的每个元素的位置,进行添加,遇到哈希碰撞将使用头插法。1.8中:将不在对每个元素重新计算hash的值只需要看看原来的hash值新增的那个bit是1还是0就好了,是0的话索引没变,是1的话索引变成“原索引+oldCap”。同时它也变成了尾插法

负载因子0.75。

threshold就是在此Load factor和length(数组长度)对应下允许的最大元素数目,超过这个数目就重新resize(扩容),扩容后的HashMap容量是之前容量的两倍。默认的负载因子0.75是对空间和时间效率的一个平衡选择,建议大家不要修改,除非在时间和空间比较特殊的情况下,如果内存空间很多而又对时间效率要求很高,可以降低负载因子Load factor的值;相反,如果内存空间紧张而对时间效率要求不高,可以增加负载因子loadFactor的值,这个值可以大于1。

HashMap的主要参数都有哪些?

transient Node<K,V>[] table; //存储键值对的数列
transient int size //键值对的数量
int threshold; //数组扩容的临界值
final float loadFactor; //负载因子

hash的计算规则?

先算出key的hashcode,然后用此hashcode与(hashcode >>> 16)相与也就是和它的高16位做与运算,最后再对table的长度进行取模。

可以看看美团技术团队的这篇文章

本文作者:xiaoovo

本文链接:https://www.cnblogs.com/xiaoovo/p/16585456.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   xiaoovo  阅读(20)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑