最详细的,最通俗易懂的HashMap原理!!!

写在前面

看过我的文章的都知道,我主打的就是一个通俗易懂,一看一个不吱声。这篇文章还是缺少一部分算法之类的技术讲解,还是现在脑海中有一个整体的框架,我怕直接讲的太深入反而一下支的太远。

HashMAP

底层结构

JDK1.8之前是数组加链表的结构,但是在JDK1.8之后就改为了数组+链表+红黑树的这个结构,具体请看下面的图。这时候你一定要有一个疑问那就是为什么要改变结构?如果你没有疑问那就得反思一下是不是缺少一些思考。先记结论后面解释,引入这个红黑树当然是为了增加查询效率。
在这里插入图片描述

put原理

首先我们初始化完map对象的时候上图中的数组是null,size是0,默认的负载因子是0.75,这个负载因子是计算扩容阈值的。当我们执行put的时候呢先判断这个数组是否是null,如果是null的情况下呢调用这个resize方法去初始化这个数组,通过hash计算key对应的数组下标,然后我们去判断这个位置是否为空,如果为空的话就生成一个node节点添加进去,这个node节点就是保存的key,value和nextnode。如果不是空的话呢判断要是红黑树就便利红黑树插入数据,如果是链表的话遍历链表,通过尾插法根据key值是否相等去判断是插入node还是覆盖node。最后还需要判断一下是否需要扩容,如果思路乱了那就跟下面这个图走一遍。
在这里插入图片描述

扩容原理

因为Map也是有一个大小的嘛,所以当插入的元素达到一定的数量就会触发map的扩容机制,那达到多大才会触发扩容呢?就是用我们的数组长度*负载因子,默认的数组长度是16,扩容因子0.75,所以就是当达到12个时就会触发扩容。我们上面提到了一个resize方法,整个扩容过程都在这里发生。JDK1.8前后扩容还有一点小区别:

1.7版本扩容首先生成两倍长度的新数组,然后便利老数组中每个位置上的链表的每一个元素,取key通过hash算法计算出在新数组中的下标并且插入元素,都转移完以后将新数组赋值给hashmap对象的table属性。

1.8版本在遍历每个节点的时候还需要判断一下是数组还是红黑树,如果是红黑树的话先统计每个下标位置的元素个数,如果元素个数超过6个就生成新的红黑树,如果没超过6过则生成链表。

为什么是6和8

哈哈哈!6和8是什么?这里说的8是当我们的链表长度大于8并且数组长度大于64的时候,我们需要讲链表转化为红黑树。当红黑树节点树小于6时再将红黑树转为链表。那么问题来了为什么是6和8?

是因为链表的时间复杂度是O(N),平均查找长度那就是N/2,而红黑树的平均查找长度是log(N),所以当元素个数达到8的时候,链表的效率就不如红黑树了。那下一个问题,为什么不是小于8在由红黑树转化为链表呢?

那是因为防止我们的元素个数在8上下抖动从而导致链表和红黑树不停的转换,这样也是很消耗性能的。懂?这里还有一个小细节,官方的告诉我们是如果hash计算的结果离散的好的话,各个值均匀分布很少出现链表很长的情况,当长度为8的时候概率为千万分之一,通常不会存这么多数据,所以很少用到红黑树。

这里有两个问题留给大家去探索一下,为什么JDK1.8由头插法改为了尾插法?为什么数组扩容是两倍(我上面的内容中把两倍加粗,不知道注意到没)?

小结

看了文章如果大家对HashMap原理有一个理解了,还是建议大家去看看源码或者找一篇讲源码的文章看一看,那会发现更多细节,也拿我这里提炼的点带回源码中验证一下,应该会有更深的感悟!!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值