如何理解HashMap

1.基本数据结构:

  •  jdk1.7,是数组+链表
  •  jdk1.8,是数组+链表+红黑树

2.树化与退化

树化意义:

  • 红黑树用来避免 DoS 攻击,防止链表超长时性能下降,树化应当是偶然情况,是保底策略
  • hash 表的查找,更新的时间复杂度是 O(1),而红黑树的查找,更新的时间复杂度是 O(log2⁡n )(log以2为底的n),TreeNode 占用空间也比普通 Node 的大,如非必要,尽量还是使用链表
  • hash 值如果足够随机,则在 hash 表内按泊松分布,在负载因子 0.75 的情况下,长度超过 8 的链表出现概率是 0.00000006,树化阈值选择 8 就是为了让树化几率足够小

树化规则:

  • 当链表长度大于树化的阈值8时,先尝试扩容来减少链表的长度,如果数组的容量已经大于等于64的时候,将链表转化为树。

退化规则:

  • 在扩容时,如果拆分树时,树元素的个数<=6时,则会退化成链表
  • 在移出remove树节点时,若根节点,左孩子,右孩子以及左孙子有一个为null时,也会退化成链表,切记,是在remove之前判断它们四个是否为null

3.索引计算

索引计算方法:

  • 首先,计算对象的 hashCode()
  • 再进行调用 HashMap 的 hash() 方法进行二次哈希
  • 二次 hash() 是为了综合高位数据,让哈希分布更为均匀
  • 最后 hash& (capacity – 1) 得到索引

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

  • 1.计算索引时候的效率更高,如果是2的n次幂,就可以使用位与运算代替取模,效率更高
  • 2.扩容时重新计算索引的效率更高,hash&oldCap==0,元素留在原来的位置;hash&oldCap!=0,新元素的位置=旧位置+oldCap(此处的Cap代表的是数组的容量)

注意:

  • 二次hash是为了配合容量 为2的n次幂这一设计前提,如果hash表的容量不是2的n次幂,则就没又必要去进行二次hash
  • 容量是2的n次幂这一设计,计算索引效果更好,但是hash的分散性就不好,需要二次hash进行补偿。但是hashTable并没有采用这一设计。

4.put与扩容

1).HashMap是懒惰创建数组的,只有在调用put方法的时候才去创建数组的。

2).计算索引(桶下标)table[i=(n-1)&hash],相当于hash值对数组容量取模。但是源码中是通过位运算&实现的,因为位运算的效率高

3).如果当前所以位置即桶下标还没有被人占用,就是此位置上没有元素,则创建Node占位并且返回

4).如果桶下标已经有人占用

  • 已经是TreeNode,走红黑树的添加或者更新逻辑
  • 是普通的Node,走链表对的添加或者更新逻辑,同时,如果链表长度超过树化阈值,则将链表转化为红黑树,再去走树化的逻辑

5).返回前检查容量是否超过阈值,一旦超过进行扩容

5.存入一个键值对的过程

1.计算hash值,取模,求出数组对应的索引值。

2.判断这个位置是否有元素,如果没有元素,则直接存入。

3.如果当前位置有元素

  • 判断当前要存入的的元素与已经存入的元素的hash值是否相等,如果不相等,再去考虑存储,如果是桶状结构,把这个数据挂载到桶上,上一个指向下一个,同时还要考虑是否需要转化为树的结构 ,如果本身就是树的结构,直接存入树中即可
  • 如果与已经存入的元素的hash值相等,就比较equals,如果equals不相等,则是两个不同的对象,按照上述进行存储。如果equals相等,则认为是同一个对象,认为两个键相等,就用新的值替换就得值

6.1.7 与 1.8 的区别

  1. 链表插入节点时,1.7 是头插法,1.8 是尾插法

  2. 1.7 是大于等于阈值且没有空位时才扩容,而 1.8 是大于阈值就扩容

  3. 1.8 在扩容计算 Node 索引时,会优化

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

  1. 在空间占用与查询时间之间取得较好的权衡

  2. 大于这个值,空间节省了,但链表就会比较长影响性能

  3. 小于这个值,冲突减少了,但扩容就会更频繁,空间占用也更多

8.key 的设计要求

  1. HashMap 的 key 可以为 null,但 Map 的其他实现则不然

  2. 作为 key 的对象,必须实现 hashCode 和 equals,并且 key 的内容不能修改(不可变)

  3. key 的 hashCode 应该有良好的散列性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

点点哇

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

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

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

打赏作者

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

抵扣说明:

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

余额充值