HashMap

HashMap

底层数据

  1. JDK1.7之前数组加链表
  2. JDK1.8之后数组加(链表或者红黑树)

为何要用红黑树,何时会树化,何时退化成链表?

当同时满足数组长度大于等于64,链表长度大于阈值8时,链表会树化

为什么也使用红黑树

1.树化是一种特殊情况,是为了避免链表超长的时候性能下降,防止DOS大量数据攻击

2.hash表的查找,更新时间复杂度为O(1),而红黑树的时间复杂度为O(log2N),TreeNode也比普通Node大,如果不是必要情况还是用链表

3.hash值如果足够随机的话,在负载因子为0.76的情况下,长度超过8的链表出现概率为0.0000006,选择8就是为了让树化概率更小

退化情况

1.在扩容拆分树的时候,树元素个数<=6则会退化成链表

2.remove时,若root、root.left、root.right、root.left.left有一个为null,退化

索引如何计算?hashCode都有了,为何还要提供hash()方法?数组容量为何是2的n次幂?

1.先计算对象的hashcode(),再进行调用hash()方法进行二次哈希,最后&(capacity-1)得到索引

2.二次hash()是为了综合高位数据,让哈希分布更均匀

数组容量为何是 2 的 n 次幂

  1. 计算索引时效率更高:如果是 2 的 n 次幂可以使用位与运算代替取模
  2. 扩容时重新计算索引效率更高: hash & oldCap == 0 的元素留在原来位置 ,否则新位置 = 旧位置 + oldCap

注意

  • 二次 hash 是为了配合 容量是 2 的 n 次幂 这一设计前提,如果 hash 表的容量不是 2 的 n 次幂,则不必二次 hash
  • 容量是 2 的 n 次幂 这一设计计算索引效率更好,但 hash 的分散性就不好,需要二次 hash 来作为补偿,没有采用这一设计的典型例子是 Hashtable

Put与扩容因子

Put流程

1.HashMap是懒加载创建数组,只有第一次使用才创建数组

2.计算索引

3.如果索引位置没人占用,创建Node并且返回

4.如果索引位置有人占用 :

​ 1.已经是TreeNode走红黑树逻辑

​ 2.是普通Node走链表逻辑,如果超过链表树化阈值就树化

5.返回前检查是否容量超过阈值,如果超过就扩容

扩容(加载)因子为何默认是 0.75f

  1. 在空间占用与查询时间之间取得较好的权衡
  2. 大于这个值,空间节省了,但链表就会比较长影响性能
  3. 小于这个值,冲突减少了,但扩容就会更频繁,空间占用也更多

多线程情况下会有什么问题

1.扩容死链(1.7)

2.数据错乱(1.7、1.8)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值