HashMap的resize扩容及put流程

说的是JDK1.8

扩容

三情况会扩容:

1、第一次put元素创建数组的时候。

2、插入节点后元素个数大于N*负载因子的时候。

3、数组小于64但是链表节点大于8。

大白话版本

Java数组是不可变的,先创建一个2倍的数组(用n << 1)左移一位的优化计算方式。

把原数组上的节点放在新数组上。根据规律rehash优化,扩容后节点要么在原位置,要么在原来的位置+数组原长度  原来的位置连接在low链上,需要移动 i+n的在High链上。把链表挂在新数组上。

原来的Index可能是树类型,移动后长度可能小于6(hashmap)有个常量,如果长度小于6就会把树转回链表。
 

put流程

hashmap的Hash算法是先把key的hashcode与自己右移16为异或运算,得到的hash值在和数组长度-1&与运算定位下标。

大白话版本

1、先看数组是否创建了,没创建就调用resize() 方法扩容

2、把 (n - 1) & Key的HashCode 定位下标 ,为null、直接插入就行

3、下标位置不为null,用equals()比较key一不一样,一样就覆盖

4、否则instanceof关键字看这个tab[i]位置是不是树类型节点,是树的节点就调用putTreeVal()按照红黑树的插入方式插入

5、不是树的节点就说明他还是链表就遍历链表(遍历人间过程还会比较key)尾插法插入链表节点

6、链表插入节点后,会看长度是否大于了8并且数组的长度不小于64

7、满足6的条件的话链表转红黑树

8、插入完成后看是否需要扩容

解释:

1.8的数组创建(调用resize方法)放在了第一次put元素的时候。

计算下标的时候(n - 1) & Key的HashCode来定位,这引出两个问题:当key没有重写HashCode方法时,两个一样的key(不同的两个对象)基本不会定位到同一个下标,就不能在遍历这个下标位置所有key 的时候比较去重。数组的长度是“2的n次幂”原因是这个长度可以用(n-1)&hashcode代替n%hashcode 。计算机硬件结构%很慢,没有专门的除法器,&就很快。

插入节点的时候链表有链表的插入方法,树有树的插入方法。

1.8改为了尾插法,因为之前头插法扩容的时候访问会出现死循环链,之前头插法的原因是认为最近插入的最近访问频率也高,但是扩容后,链表位置又倒置了,不如直接改成尾插了。

链表不是大于8了就一定转树,当数组长度不够64的时候会先扩容

插入节点后看是否需要扩容,(做LRU缓存的时候也是插入后看需不需要移除元素)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值