一、举例说明
例子:
-
hashmap原容量 oldCap = 16(二进制:
0001 0000) -
hashmap新容量 newCap = 32
-
hash1 = 33,hash2 = 17
明确以下事项前提:
-
hash值,由hash函数决定,扩容不影响hash值
-
新位置(也就是桶下标),受扩容影响,可能变,可能不变,如何判断新位置就是本文要讲的内容
-
位置(桶下标)的计算 index = hash & (cap - 1),其中cap为2的n次方
项目 不移动示例(hash1 = 33) 移动示例(hash2 = 17) hash(十进制) 33 17 hash(二进制) 0010 00010001 0001oldCap(二进制) 0001 00000001 0000原桶下标 = hash & (****oldcap- 1)33 & 15 = 117 & 15 = 1原桶下标(二进制) 0010 0001& 0000 1111= 0000 00010001 0001& 0000 1111= 0000 0001hash & oldcap33& 16= 017& 16= 16hash & oldcap(二进制)00100001& 00010000= 0000000000010001& 00010000= 00010000高位 0 1 是否移动 ==0 不移动 != 0 移动 新桶下标 = hash & (32 - 1)33& 31= 117& 31= 17= 1+ 16新桶下标(二进制) 0010 0001& 0001 1111= 0000 00010001 0001& 0001 1111= 0001 0001
二、解释
2.1 什么是高位?
高位就是数字的二进制最左边 那个位,比如:
16,二进制为10000,高位就是5;
64,二进制为1000000,高位就是7;
2.2 java8以后,HashMap 扩容时如何确定某个元素的新位置?
hash值 与 老数组长度oldcap 进行按位与运算 ,得到的结果 ,看它是否为0:
为0,则 不移动 ,
不为0,则 新位置=老位置+老数组长度
用公式描述:

或者也可以看高位,二者本质相同
hash值 与 老数组长度oldcap 进行按位与运算 ,得到的结果 ,看它"对应老数组高位 "是否为0:
为0,则 不移动 ,
为1,则 新位置=老位置+老数组长度
表格,红色字体那里标的很清晰
三、源码解析
java
if ((e.hash & oldCap) == 0) {
// 高位为 0,不移动
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
} else {
// 高位为 1,移动到 oldIndex + oldCap
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
3.1 这段代码在做什么
判断 hash 在"扩容新增的那一位"上是 0 还是 1
两种结果,对应两种新索引
情况一:高位 = 0(不移动)
(e.hash & oldCap) == 0
-
新索引 = 旧索引
-
仍然落在原桶位置
数学等价于:
hash & (newCap - 1) == hash & (oldCap - 1)
情况二:高位 = 1(发生移动)
(e.hash & oldCap) != 0
- 新索引 = 旧索引 + oldCap
也就是:
newIndex = oldIndex + oldCap