HashMap1.7和1.8原理解析

HashMap1.7原理:

HashMap的底层实现是:数组 + 链表结构;

负载因子:

1.HashMap的初始化容量是16,负载因子是0.75,当元素个数达到 16*0.75 = 12 时,HashMap就会进行扩容。扩容就会进行reHash(为key重新计算存放位置),复制数据。非常消耗性能。

2.通常如果可以指定HashMap的大小最好,可以减少扩容带来的性能消耗。

其实真正存放数据的是HashMap内部的静态类Entry <k,v> []  table,他有key,value,next,hash(key的hashcode值)成员变量。

put()

新增元素时:

1.先计算出key的hashcode值;

2.根据hashcode定位内存地址;

3.如果该地址没有值,那么直接添加进去;

4.如果该地址只有一个值,那么比较key,hashcode如果相同,那么覆盖并且返回原来的值,反之新值和旧值组成链表,新值放入数组,旧值是新值的下一个。

5.如果该地址是一个链表,那么遍历链表比较key,hashcode如果相同,那么覆盖并且返回原来的值,反之将新值插入数组,新值指向原链表。

get()

获取数据时:

1.计算出key的hashcode值

2.之后根据hashcode定位位置

3.该位置的key,hashcode和传入的key,hashcode是否相同,是就返回value。

4.如果该位置是链表,则遍历比较key,hashcode,找到相同的,就返回value。

5.该位置为空,或者找不到相同的,就返回null。

HashMap1.8原理:

底层结构:数组 + 链表/红黑树;

当hash冲突严重的时候,链表会越来越长,影响查询效率,时间复杂度为O(N)(表示该算法为线性算法),因此1.8重点优化了查询效率。

TREEIFY_THRESHOLD :将单链表转化为红黑树的阈值。

HashEntry修改为Node。

put()

新增元素时:

1.跟1.7相比就是如果该位置是链表,就往后面添加,如果是一个值,就和旧值形成链表,新值在旧值后面。

2.如果该位置是红黑树,就按红黑树的方式写入值。

3.接着判断当前的链表的大小是否大于阈值,大于时需要将链表转化为红黑树。

4.如果在遍历过程中,key相等直接退出遍历。

5.最后判断是否需要扩容。

get()

获取数据时:

1.跟1.7相比当根据hashcode值得到位置时,该位置为null,就返回null;

2.如果第一个值跟传入的key相等,就返回该value,如果不是,那么判断是红黑树,还是链表。

3.链表遍历比较,返回值。

4红黑树按红黑树的方式查找,返回值。

HashMap底层为什么不安全?

虽然1.8改为红黑树之后,查询效率提高到了O(logn)。但是原有的问题还是存在:在扩容的时候,并发操作还是容易形成环形链表,当查询一个不存在的key时,而计算出的下标刚好是环形链表的下标。就会造成死循环。

HashMap如何解决hash冲突?

HashMap通过链表来解决散列碰撞问题,当发生冲突时,该键值对对象会存储在链表的下一个节点上。当不同的键却有相同的hashcode值时,他们会被存储在数组同一位置的链表中。

 

参考文章:https://juejin.im/post/5e5c5c52f265da575f4e7558#heading-23

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值