hashmap 扩容是元素还是数组_HashMap扩容机制

HashMap是Map的实现类,一般我们说集合的扩容机制,一般是发生在数据存入的过程中,在分析扩容机制前我们先看看HashMap的数据存储结构,在JDK1.8版本中,HashMap数据存储在Node数组中

transient Node[] table;

Node为HashMap的一个静态内部类,包含了hash值,存入元素的key,value,以及下一个元素的指针四个属性。

调用HashMap的put方法,首先会根据存入元素的key计算hash值,计算方法为

如果key为空,hash=0,否则对key进行hashCode运算,同时取hashCode值的高16位进行异或运算得到hash值,目的是使hash值更散列。

static final int hash(Object key) {

int h;

//如果key为空,说明hashMap的key可为空

return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

}

计算好key的hash值后,如果是首次添加数据,则Node[]数组为空,会进行第一次扩容操作,设置默认初始容量为1 << 4=16,初始阈值为16*0.75=12,并创建一个新的长度为16的Node数组,然后计算数组下标=(15&hash)是否存在元素,如果不存在,则将hash,key,value,null组成的Node对象存入该下标位置,

当该数组中存入的元素长度达到阈值时,也即12位时,又会发生扩容,先判断原数组长度是否大于等于能够分配的长度上限-2的30次方,如果达到,则不再扩容,并将阈值设置为Integer.MAX_VALUE,2的31次方-1,否则将原数组扩容至新容量为原数组额两倍,阈值也扩大至原来阈值的两倍,设置好要扩容的容量后,接下来就开始根据新的容量创建新的Node数组,遍历原数组,将原数组里的

数据转移到新数组中,如果原数组元素的next指针为空,说明不存在链表结构,

if (e.next == null)

newTab[e.hash & (newCap - 1)] = e;

则元素转移到新数组的下标计算方式为上图所示,通过元素的hash值与新数组容量-1做与运算,这么做的目的也是为了使数据更加的散列,与运算的逻辑是必须同时为1才等于1,这样就减少了hash碰撞的概率,举个例子,如果新容量为32,则其二进制为100000,如果用该二进制去进行与运算时,基本上都为0,hash碰撞的概率很大,但是一旦减1后变为31,其二进制变为11111,进行与运算时变为0或1的概率都比较均匀,发生hash碰撞的概率就会小很多,这也同时解释了为什么扩容的容量要是2的倍数,就是为了这一步减1做准备的,否则就没有必要减1了。如果原数组元素的next指针不为空,则会判断是否为红黑树结构或者为链表结构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值