铺垫
1、a%=a&(
-1)。即a与2的n次方的数取余,等于a与此值减一后的值按位取与。
2、a%=x,则a%
=x,或者a%
=x+
。
3、a%=x,如果a&
=0,则a%
=x否则a%
=x+
。
上述铺垫内容,在后期博客证明:
HashMap查找过程
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
//由铺垫1得出(n-1)&hash相当于hash%n 根据key的hash值查找到key所在的数组下标
//判断链表的第一个元素是否是待查找的数据
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
//如果链表第一个元素不是待查找的数据,则进行遍历查找(树形查找或者链表遍历查找)
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
HashMap 扩容过程
final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
//数组长度扩容2倍,阈值扩容2倍
if (oldCap > 0) {
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
}
else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr;
else { // zero initial threshold signifies using defaults
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
if (newThr == 0) {
float ft = (float)newCap * loadFactor;
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
(int)ft : Integer.MAX_VALUE);
}
threshold = newThr;
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
table = newTab;
if (oldTab != null) {
//开始遍历老的数组列表
for (int j = 0; j < oldCap; ++j) {
Node<K,V> e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
//如果当前数组下边对应的链表只有一个元素,则直接用key ,hash对新扩容的数组取余,找到对应扩容数组的位置。
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e;
else if (e instanceof TreeNode)
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order
//挨个遍历当前链表中的元素,根据新数组的长度重新分配数组位置
//根据铺垫2,犹豫新数组是原始素组长度的2倍,所以链表中的元素hash后取余,新位置要么不变,要么就是原始位置+原数组长度。
//根据铺垫3判断新元素链表位置是在原始位置还是在原始位置+原始数组长度位置
//保存位置不变的链表元素
Node<K,V> loHead = null, loTail = null;
//保存位置发生变化的链表元素,原始位置+原数组长度
Node<K,V> hiHead = null, hiTail = null;
//head为链表的头。tail为链表的尾部,随着遍历元素,不断向尾部添加元素。
Node<K,V> next;
do {
next = e.next;
//根据铺垫3,判断链表元素位置是否发生变化
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
}
else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
//将位置不变的链表元素重新赋值到新的数组下标j
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
//将位置发生变化的链表元素重新赋值到新的数组下标j+oldCap(原数组长度)
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}