Map之HashMap

1. HashMap的底层结构是数组+链表,1.7中和1.8中又不一样,1.8中加入了红黑树

2. 每个数组都是以key-value形式存储的,1.7中叫entry,1.8中叫node

3. HashMap一开始默认长度是16,put的时候会将key值通过公式得到一个index,index = HashCode(key)& (length - 1),这个index就是在数据中的位置

4. put的时候也会判断是否需要扩容resize,是否需要resize有两个因素影响,一个是capacity(map长度),一个是loadFactor(负载因子,默认是0.75f),当长度大于 capacity*loadFactor时才会去扩容,例如长度是16,16*0.75=12,当put第13个元素的时候就会去扩容。

5. 扩容主要分为两步,①创建一个长度是当前数组长度两倍的数组,②将老数据编辑并重新计算index到新数组中

6. put时如果出现hash碰撞,就是计算得到的index值是一样的,但是key的地址和内容不一样, 就会在数组中的一个位置上形成链表

7. 在1.7的时候插入链表采用头插法,在1.8中改为了尾插,因为头插在1.7中如果是多线程下会导致Infinite Loop(无限循环),例如A线程和B线程都进入了resize,A中链表关系是 1->2->null的,数组转移后就是 2->1->null,此时B线程执行,因为B线程当时保存的关系是1->2->null,再去遍历A线程的新数组就有可能导致链表成环了。1.8改为了尾插法,保证在新的数组中是原来的顺序,但是1.8中也不能保证线程安全,因为有可能在多线程情况下上一秒put的值,下一秒get拿到的是另外的值。

8. 在1.8中如果链表的长度大于等于8就会转换为红黑树,当小于7时又会转换为链表,因为链表查询复杂度是O(n),红黑树查询复杂度是O(logN),比链表快,以7作为一个分水岭

9. hashMap默认初始值是16,减1就是15,他的2进制是1111,然后计算key得到的hashcode与1111做位与运算最终会将数据均匀分布到数组上,这也就是为啥作者用2的幂的数字,位与运算比算数运算快

10. 想要hashmap线程安全,可以直接使用hashtable或者concurrentHashmap或者Collections.synchronizedMap(Map)创建线程安全的map集合, hashtable是直接粗暴在每个操作方法上加锁,concurrentHashmap的1.7和1.8有所区别,但是并发度比hashtable要好。

11. hashmap,hashtable,concurrentHashmap,Collections.synchronizedMap(Map)区别

①Collections.synchronizedMap 中有个mutex排斥锁,对于一些操作方法的外围锁住这个mutex对象,其实和hashtable操作一样,不过一个锁方法,一个锁方法里面的外层代码

②hashtable和concurrentHashmap都是不能put key或value为null的值,因为它俩是线程安全的,支持并发,所以当多个线程get的时候,假如是个null,就没办法确定key是不存在还是说key的值为null,然后如果再去执行obj.contains操作,又可能obj的值就变了,没办法支持到线程安全和并发的特性

③hashtable和hashmap继承的类不同;初始容量不同,hashmap是16,hashtable是11;扩容机制也不一样,hashmap是翻倍,hashtable是翻倍+1;迭代器不同,hashmap是快速失败(fail—fast)机制,而hashtable不是的,例如hasmap在迭代过程中增加,删除,修改,都会抛出Concurrent Modification Exception异常

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

翅膀君

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

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

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

打赏作者

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

抵扣说明:

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

余额充值