Java面试宝典:你一定不知道的 HashMap

 考点:
     1. HashMap的底层数据结构?
     2. HashMap的存取原理?
     3. Java7和Java8的区别?
     4. 为啥会线程不安全?
     5. 有什么线程安全的类代替么?
     6. 默认初始化大小是多少?为啥是这么多?为啥大小都是2的幂?
     7. HashMap的扩容方式?负载因子是多少?为什是这么多?
     8. HashMap的主要参数都有哪些?
     9. HashMap是怎么处理hash碰撞的?
     10. hash的计算规则?
  • #负载因子

  当 负载因子 < 0.75 时,数组中元素较少时即触发扩容,时间效率提升(链表相对较少,取值直接hash),空间利用率降低

  当 负载因子 > 0.75 时,数组中元素较多时才触发扩容,时间效率降低(链表相对较多,取值需进行查找),空间利用率提升

  当 负载因子 = 0.75 时,空间利用率较高,可避免相当多的 hash 冲突(降低了链表/红黑树的高度),且取值基本可直接hash

  • #init

  阿里巴巴插件规范:在初始化HashMap时尽量赋初值且值为2^n

  HashMap默认初始长度为 1<< 4 (16)

  索引的计算方式为 `index = (n - 1) & hash` _(其中 n = key.length())_

  所以为了尽量使key的对应索引值分布均匀,可将值设为 2^n 使得 (n - 1) = 0b1111111...,index 的值等同于hashCode的后几位。即只要输入的 hashCode 本身分布均匀,hash算法结果就是均匀的(减少干扰)

  这是为了实现均匀分布

  • #put

  HashMap使用链表+数组的方式储存节点 (1.7 Entry 1.8 Node)

  在Java8以前,对于重复数据采用的是头插法(作者认为新插入的值被查找的可能性更大),从Java8开始改用尾插法

  HashMap进行扩容时先将数组长度扩容,然后枚举数组所有位置对存在的列表的所有节点重新计算哈希值,当使用头插法时可能导致链表倒序,多线程下还有形成环形链表的风险

1. 原链表

 

2. 倒序

  3. 闭环

 

  因为扩容前后结点顺序不变,故1.8以后使用尾插法时不会出现上述两种情况。但仍无法保证线程安全(方法未加锁) 

参考文章

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值