《HashMap的数据结构》

HashMap在JDK1.7中使用数组+单向链表(头插法),而JDK1.8则采用数组+单向链表(尾插法)+红黑树。其核心数据结构table存储键值对,通过哈希算法处理冲突,当链表长度超过8且数组长度超过64时,链表转为红黑树。加载因子影响扩容时机,当元素数量超过数组容量的75%时触发扩容至两倍。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

底层数据结构的组成

JDK 1.7——数组+单向链表(使用头插法)

JDK 1.8——数组+单向链表(使用尾插法)+红黑树

关键参数

1.table:保存KV键值对的数组(Node<K,V>类型);Node<K,V>表示哈希表中的节点,K和V分别表示键和值的类型。当我们往HashMap中添加键值对时,会重新计算key的hash值,然后保存在table数组里。

 2.单向链表:Node<K,V>

当我们添加KV键值对时,会调用put方法,然后将key传给hash()函数

 在hash()方法中,首先判断key是否为null,如果key为null,算出来的hsah值就为0,此时计算出来的下标肯定就为0,那就将此元素放入数组下标为0的位置;如果下标不为null,就将key自己的哈希值赋值给h,然后将h右移16位(相当于除以2的16次方),再将h与原来的值进行异或运算,得到最终的哈希值。这样做的目的是降低哈希冲突。计算出key的哈希值后,就可以将元素存入数组中。但是具体存入什么位置,得调用putval()方法。

将计算出来的哈希值,value,key都传给putval()方法,首先声明临时数组tab,当前结点p,将table的引用传给tab,如果tab数组等于null(用无参构造方法,不给数组分配容量),或者tab数组的长度等于0,就调用resize()方法对数组进行第一次扩容,然后拿到数组的长度。

resize()方法中, 刚开始给数组的长度默认分配16。

 给数组分配好长度后,就要考虑元素到底存在数组的哪个位置。通过数组的长度减一和hash值做"与"运算(数组长度必须为2的n次幂)计算出数组中的索引i,如果该位置为null,则直接将新节点插入到该位置。

 

如果该位置已经存在元素(此时产生下标冲突),就先判断如果当前节点的hash值和计算出来的hsah值一样并且当前key和已存在节点的key一样,内容也一样,就做覆盖操作。

 

然后,再判断此节点类型,如果类型为树,就把此节点放入二叉查找树中。

 

否则就是链表类型,首先,初始化一个用于记录当前链表长度的变量binCount,然后循环,每次循环时先判断当前节点的下一个节点是否为空,如果为空,说明当前节点是链表的最后一个节点,可以将新节点插入到它的下一个节点的位置上,并且如果当前链表长度大于等于TREEIFY_THRESHOLD-1(TREEIFY_THRESHOLD是一个常量值为 8),则调用treeifyBin()方法将链表转换成红黑树,然后跳出循环。

 

在转为红黑树之前,会再判断如果数组的长度小于MIN_TREEIFY_CAPACITY(MIN_TREEIFY_CAPACITY是一个常量值为 64),则先不转换成红黑树,调用resize()方法对数组扩容。如果在相同位置上链表的长度超过8并且数组的长度超过64了,

此时,将链表转换成二叉数。

 3.LoadFactor:加载因子(填充因子) 

当添加第一个KV键值对时(使用无参构造方法):数组默认容量为16,加载因子为0.75。

加入元素,如果链表长度大于阈值(默认为8)并且数组长度小于64,会产生数组扩容。

添加元素后,当HashMap中的元素个数超过【数组大小×加载因子(LoadFactor)】时,原数组扩容2倍,例如:加载因子的默认值为0.75,数组容量默认为16,当HashMap中元素的个数超过16×0.75的时候,数组的容量扩容为32。

4.threshold:阈值(数组大小×加载因子(LoadFactor))

当数组的长度超过阈值时,调用resize()方法进行数组的扩容。

如果旧容量左移一位后小于最大容量(MAXIMUM_CAPACITY值为:2的30次方),并且旧容量大于或等于默认容量(DEFAULT_INITIAL_CAPACITY),则将新容量设置为旧容量左移一位(旧容量×2)。

总结:1.通过 & 运算确定元素在数组中的位置,会提高效率。

2.加载因子代表了HashMap对数组容量的使用率,加载因子越高,表示允许填满的元素就越多,集合的空间利用率就越高,但是冲突就会增加。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值