Java源码解析|HashMap的前世今生

HashMap的前世今生

Java8在Java7的基础上,做了一些改进和优化。
底层数据结构和实现方法上,HashMap几乎重写了一套
所有的集合都新增了函数式的方法,比如说forEach,也新增了很多好用的函数。

前世——Java 1.7 底层数据结构

数组 + 链表

在Java1.7中HashMap使用数组+链表来作为存储结构
数组就类似一个个桶构成的容器,链表用来解决冲突,当出现冲突时,就找到当前数据应该存储的桶的位置(数组下标),在当前桶中插入新链表结点。

如下图所示:

Alt text

链表结点中存放(key,value)键值对

Alt text

扩容与初始化

初始化:初始时,HashMap的数组大小(桶个数)默认为16,且数组大小必须是2的幂次方
看下图源码注释所示

Alt text


Alt text

resize方法扩容
什么时候扩容?
桶里链表结点元素超过threshole变量= 16 * 扩容因子0.75 = 12个时开始扩容

Alt text


限定扩容最大值为Integer的大小

Alt text

扩容一倍:

Alt text

怎么扩容:开辟新的数组(桶),使用transfer方法将旧数组数据拷贝到新数组中,部分元素重写计算hash值(rehash)

Alt text


Alt text

transfer函数,把旧表的桶搬到新的桶
遍历每一个桶的链表,重新rehash,indexFor拿到新表的下标,放到新表

Alt text

hash算法

为什么数组的大小必须为2的幂
我们在求key的hash值在数组的下标的方法中发现 数组设置为2的幂­,是为了在求模转成位运算时,恰好可以得到数组下标

Alt text

举个栗子:比如,假设 数组长度为2的5次方,也就是32个长度,我们拿key的hash值(32位)与数组长度作&与运算,就能得到一个在数组长度范围内的下标,这个下标就是当前key应该在表table的位置了。
看下图演示吧:

Alt text

所以数组大小必须规定为2的幂的原因就是为了hash算法将来计算key在数组中的index下标

由key得到hashcode的算法,在1.7中比较复杂,就不过多陈述了。

put方法

需要使用equals方法比较key,所以自定义的类需要重载equals方法

因此也推荐使用String这种已经重写equals方法的类作为键key。

Alt text


Alt text

遗留问题:安全、死锁

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wspxsp.html