在put和get方法中都需要根据key找到table中的index,源码为:
n = table.length
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
i = (n - 1) & hash(key)
关键就在于最后一句,
(n - 1) & x x为任意值时候 此值小于n
例:n=32 = 2<<4 = 10 0000
n-1 = 01 1111 与任意值做与运算 5位之上都是0
分析一下扩容方法对于每个NodeList元素重新排位过程
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) {
Node<K,V> e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e; //如果table此节点只有一个节点 直接复制
else if (e instanceof TreeNode)
((TreeNode<K,V>)e).split(this, newTab, j, oldCap); //树形节点处理
else { // preserve order
Node<K,V> loHead = null, loTail = null; //拆分低位NodeList
Node<K,V> hiHead = null, hiTail = null; //拆分高位NodeList
Node<K,V> next;
do {
next = e.next;
if ((e.hash & oldCap) == 0) { //对于e.hash x()位上为0的Node,就算重新计算index也还是会落在原index上
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
else { //对于e.hash x()位上为1的Node,重新计算index也还是会落在原index+oldCap上
if (hiTail == null) //上述过程就是把一个nodelist根据key的hash的x位值,分解成两个nodelist
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
例:
扩容前oldn=32 = 2<<4 = 010 0000 oldn-1=0<span style="color:#FF6666;">0</span>1 1111
扩容后newn=64 = 2<<5 = 100 0000 newn-1=0<span style="color:#FF6666;">1</span>1 1111 红色表示x位
那么对于table[index]处的nodelist的key,hash(key) & oldn == 0的也就是hash(key)x位为0的,元素最终还是会落在index处,把这样的node分离出来,连接在一起放在
table[index]处
同理反之的放在table[index+oldn]处