Java -HashMap

HashMap

参考链接:

  • https://tech.meituan.com/2016/06/24/java-hashmap.html
  • https://juejin.im/post/6844903588179755021#heading-14

| HashMap就是使用哈希表来存储的。哈希表为解决冲突,可以采用开放地址法和链地址法等来解决问题,Java中HashMap采用了链地址法。
| 链地址法,简单来说,就是数组加链表的结合。

当链表的长度大于8的时候,转换为红黑树。
横的是数组,竖的是链表
[4]
|
[3]
|
[2]
|
[1]
|
[1][2][3][4][5]

计算bucket下标

Hash算法本质:取Key的hashcode值、高位运算、取模运算

方法一:
static final int hash(Object key) {   //jdk1.8 & jdk1.7
     int h;
     // h = key.hashCode() 为第一步 取hashCode值
     // h ^ (h >>> 16)  为第二步 高位参与运算
     return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
方法二:
static int indexFor(int h, int length) {  //jdk1.7的源码,jdk1.8没有这个方法,但是实现原理一样的
     return h & (length-1);  //第三步 取模运算
}

详细可以参考:https://juejin.im/post/6844903588179755021#heading-11

扰动

扰动:为了减少冲突,因为直接计算hashcode的话发生冲突的概率很高
hash方法中进行扰动的解释:
https://www.zhihu.com/question/51784530

Put方法

添加元素过程:

如果 Node[] table 表为 null ,则表示是第一次添加元素,讲构造函数也提到了,及时构造函数指定了期望初始容量,在第一次添加元素的时候也为空。这时候需要进行首次扩容过程。
计算对应的键值对在 table 表中的索引位置,通过i = (n - 1) & hash 获得。
判断索引位置是否有元素如果没有元素则直接插入到数组中。如果有元素且key 相同,则覆盖 value 值,这里判断是用的 equals 这就表示要正确的存储元素,就必须按照业务要求覆写 key 的 equals 方法,上篇文章我们也提及到了该方法重要性。
如果索引位置的 key 不相同,则需要遍历单链表,如果遍历过如果有与 key 相同的节点,则保存索引,替换 Value;如果没有相同节点,则在但单链表尾部插入新节点。这里操作与1.7不同,1.7新来的节点总是在数组索引位置,而之前的元素作为下个节点拼接到新节点尾部。
如果插入节点后链表的长度大于树化阈值,则需要将单链表转为红黑树。
成功插入节点后,判断键值对个数是否大于扩容阈值,如果大于了则需要再次扩容。至此整个插入元素过程结束。

扩容resize方法

扩容(resize)就是重新计算容量,向HashMap对象里不停的添加元素,而HashMap对象内部的数组无法装载更多的元素时,对象就需要扩大数组的长度,以便能装入更多的元素。当然Java里的数组是无法自动扩容的,方法是使用一个新的数组代替已有的容量小的数组,就像我们用一个小桶装水,如果想装更多的水,就得换大水桶。

疑问:最大存储容量为什么是 2的30次方

面试题:
HashMap线程不安全在哪?

  1. 数据覆盖问题
  2. 1.7 扩容时容易导致死循环

https://juejin.im/post/6844904013909983245#heading-28

如何是规避HashMap的线程不安全?

  1. 将Map转为包装类
Map<String, Integer> testMap = new HashMap<>();
...
// 转为线程安全的map
Map<String, Integer> map = Collections.synchronizedMap(testMap);

  1. 使用ConcurrentHashMap
    Map<String, Integer> susuMap = new ConcurrentHashMap<>();
    并发环境下应该使用ConcurrentHashMap
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值