HashMap resize method

// Expand and initialize
final Node <K, V> [] resize () {
Node <K, V> [] oldTab = table;
int oldCap = (oldTab == null)? 0: oldTab.length; // array length
int oldThr = threshold; // Threshold value
int newCap, newThr = 0;
if (oldCap> 0) {
// Expansion
if (oldCap> = MAXIMUM_CAPACITY) {
// The length of the original array is greater than the maximum capacity (1073741824), then set the threshold to Integer.MAX_VALUE = 2147483647
// Close to twice MAXIMUM_CAPACITY
threshold = Integer.MAX_VALUE;
return oldTab;
} else if ((newCap = oldCap << 1) <MAXIMUM_CAPACITY && oldCap> = DEFAULT_INITIAL_CAPACITY) {
// The new array length is the original 2 times,
// the critical value is also expanded to 2 times
newThr = oldThr << 1;
}
} else if (oldThr>0) {
// If the original threshold is greater than 0, set the capacity to the original threshold
// This will
happen when the parameter is initialized for the first time newCap = oldThr;
} else {
// This will happen when there is no parameter initialization by default
newCap = DEFAULT_INITIAL_CAPACITY; // 16
newThr = (int) (DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY ); // 0.75 * 16 = 12
)
if (newThr == 0) {
// If the new capacity == 0
float ft = (float) newCap * loadFactor; // loadFactor The hash load factor defaults to 0.75, which can be initialized When passing in, 16 * 0.75 = 12 can put 12 key-value pairs
newThr = (newCap <MAXIMUM_CAPACITY && ft <(float) MAXIMUM_CAPACITY? (Int) ft: Integer.MAX_VALUE);
}
threshold = newThr; // The threshold will be Set to new threshold
@SuppressWarnings ({"rawtypes", "unchecked"})
// Capacity expansion
Node <K, V> [] newTab = (Node <K, V> []) new Node [newCap];
table = newTab ;
// If the original table has data, copy the data to the new table
if (oldTab! = null) {
// Loop the entire array according to the capacity, copy the non-empty elements
for (int j = 0; j <oldCap; ++ j) {
Node <K, V> e;
// Get The jth element of the array
if ((e = oldTab [j])! = Null) {
oldTab [j] = null;
// If there is only one linked list, then directly assign
if (e.next == null)
// e.hash & (newCap-1) determine the storage location of the element
newTab [e.hash & (newCap-1)] = e;
// omit the red and black tree
else {
// copy the linked list
// the method is special: it
Instead of recalculating the position of the element in the array // the original position plus the length of the original array is used to calculate the position
Node <K, V> loHead = null, loTail = null;
Node <K, V> hiHead = null , hiTail = null;
Node <K, V> next;
do {
/ ********************************** *********** /
/ **
* Note: e itself is a node of a linked list, it has its own value and next (the value of the linked list), but because the next value does not help the expansion of the node,
* all in the discussion below, I approximate that e is a self-only value Without elements with next values.
* /
/ ********************************************* /
next = e.next;
// Note: not (e.hash & (oldCap-1)); but (e.hash & oldCap)

// (e.hash & oldCap) gets whether the position of the element in the array needs to be moved, the example is as follows
// Example 1:
// e.hash = 10 0000 1010
// oldCap = 16 0001 0000
// & = 0 0000 0000 The first bit of the higher order 0
// Conclusion: The position of the element has not changed in the array after the expansion

// Example 2:
// e.hash = 17 0001 0001
// oldCap = 16 0001 0000
// & = 1 0001 0000 The first higher bit 1
// Conclusion: The position of the element in the array has changed after the expansion. The new subscript position is the original subscript position + the original array length

// (e.hash & ( oldCap-1)) gets the subscript position, the example is as follows
// e.hash = 10 0000 1010
// oldCap-1 = 15 0000 1111
// & = 10 0000 1010

// e.hash = 17 0001 0001
// oldCap-1 = 15 0000 1111
// & = 1 0000 0001

// New subscript position
// e.hash = 17 0001 0001
// newCap-1 = 31 0001 1111 newCap = 32
// & = 17 0001 0001 1+ oldCap = 1 + 16

// After the element recalculates the hash, because n becomes 2 times, then the mask range of n-1 is 1bit (red) in the high order, so the new index will change like this:
// Refer to the blog post: [Java8 Detailed Explanation of HashMap] (https://blog.csdn.net/login_sonata/article/details/76598675)
// 0000 0001-> 0001 0001

if ((e.hash & oldCap) == 0) {
// If the position of the original element has not changed
if (loTail == null)
loHead = e; // Determine the first element
/// The first entry e-> aa ; loHead-> aa
else
loTail.next = e;
// When entering for the second time, loTail-> aa; e-> bb; loTail.next-> bb; and loHead and loTail refer to the same block of memory, so loHead. next address is bb
// on the third entry loTail-> bb; e-> cc; loTail.next address is cc; loHead.next.next = cc
loTail = e;
// first entry e-> aa ; loTail-> aa loTail points to the same memory space as loHead
// the second time you enter e-> bb; loTail-> bb loTail points to the same memory space as loTail.next (loHead.next) loTail = loTail. next
// when entering for the third time e-> cc; loTail-> cc loTail points to the same memory as loTail.next (loHead.next.next)
} else {
// same as above

if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next)! = null); // This piece is the old linked list migration new linked list
// Summary: the relative position of the old linked list migration new linked list linked element in 1.8 is not Change; the actual operation is on the memory address of the object
// in 1.7, the old linked list migrates to the new linked list. If the array index position of the new table is the same, the linked list elements will be inverted
if (loTail! = Null) {
loTail.next = null; // Set the next node of the linked list to empty
newTab [j] = loHead;
}
if (hiTail! = Null) {
hiTail.next = null; // Set the next node of the linked list to empty
newTab [j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}

Guess you like

Origin www.cnblogs.com/misliu/p/12717833.html