9.HashMap和ArrayList

1 HashMap

重要成员变量

① 负载因子:默认为 0.75,表示 HashMap 存储的元素数到达 HashMap 散列数组长度的 0.75 时就进行扩容

  • 负载因子也可以认为是存储的元素有多少个,当然,散列数组中的元素个数越多,内存利用率就告,但是hash冲突的概率也会很高

  • 负载因子越大,散列数组的内存利用率越高,但哈希冲突概率也越高,查询效率相对降低;

  • 负载因子越小,散列数组的内存利用率越低,但哈希冲突概率越低,查询效率相对较高

② 散列数组:HashMap 通过分离链表法解决哈希冲突的问题,在散列数组中存储的就是链表中的一个个头节点

③ K-V 键值对:K-V 键值对以 Node 节点的方式进行存储,Node 继承自 Map.Entry,包含 Next 指针,Key,Value 和 hash

④ threshold:就是 负载因子 * 数组容量(其实就是数组元素到达总数组的多少才进行扩容)

⑤ size:HashMap 中当前存储的节点数


put方法流程:

需要注意:HashMap 允许插入键为 null 的键值对。但是因为无法调用 null 的 hashCode() 方法,也就无法确定该键值对的桶下标,只能通过强制指定一个桶下标来存放。HashMap 使用第 0 个桶存放键为 null 的键值对。

① 再哈希:首先通过key获取到hashCode值,然后这个hash值要与数组的长度-1进行与运算来确定该值应该放到数组那个位置。

  • 目的:在对散列数组长度取余时,高位通常不参与运算,再哈希让高位参与哈希运算,让低位尽量不同,使哈希分布更均匀

② 检查散列数组是否为空,若为空,初始化散列数组,数组容量将会初始化为16

③ 若 Key 的 HashCode 对应的散列数组位置上节点为空,则直接将新节点加入

④ 若不为空,比较链表的头节点 Key 与 put Key 是否相等,先比较 hashcode,再比较(== || equals),若相等,进行更新,若不相等,顺着链表按同样的逻辑进行比较

⑤ 若是 1.8 的HashMap,会先判断链表的头节点是否是 TreeNode,若是,则按照红黑树的逻辑进行插入

⑥ 1.7 的 HashMap 中,若遍历完链表仍未找到 Key 相同的节点,则将新节点加入到链表头,会造成并发扩容的死链问题,1.8 中,将头插法改为了尾插法,解决了死链问题,但并发环境下的其他基本问题,如更新丢失等,仍然没有解决

  • 1.8 以前一直采用头插法的是由于计算机的局部性原理,即一个最近被访问过的对象,很有可能很快会被再访问到,基于该假设,在头节点插入,可以有效的提高查询的效率,在发生并发问题时,完全可以使用 concurrent map来解决

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值