# Interpretation of HashMap source code (gradual improvement)

1. Initialization

```HashMap map= new HashMap(16);

Initial value
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
Maximum
static final int MAXIMUM_CAPACITY = 1 << 30;
static final float DEFAULT_LOAD_FACTOR = 0.75f;
The threshold value of chain table to tree
static final int TREEIFY_THRESHOLD = 8;
Threshold value of tree fallback list
static final int UNTREEIFY_THRESHOLD = 6;
Minimum capacity of tree
static final int MIN_TREEIFY_CAPACITY = 64;```

2. put method

``````public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}

static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); //Disturbance function
}``````

In fact, hashmap is the hash structure of array + linked list. Through the hashcode of the incoming key, we can get its subscript through a disturbance function and array capacity redundancy (why to use disturbance function: first of all, the length of general hashmap is less than 16 bits, while the hashcode value of key is int type, which is 32 bits. If we directly use hashcode and capacity redundancy, the lower 16 bits will not change, the higher 16 bits In the case of bit change, the lower edge of the array is consistent, which is easy to hash conflict. Therefore, the higher 16 bits are also included in the calculation, which effectively reduces the conflict probability.)

no talk show code: insert hashmap method

``````final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
//If the array is empty or the capacity is empty, the capacity is expanded. The default capacity is 16 and the threshold value is 12
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
//There is no hash collision, put it directly into the corresponding position of its subscript
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
//In hash collision, the chain list method is to organize the objects with the same hash value into a chain list and place it in the slot corresponding to the hash value
else {
Node<K,V> e; K k;
//The key passed in is the same as the header node of the linked list, which is directly overwritten
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
//The current collision node is already a red black tree
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
//No red black tree generated
else {
for (int binCount = 0; ; ++binCount) {
//Put the new node in its tail. If the number of collision nodes is greater than or equal to 8, call the tree method
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
//The key passed in is the same as one of the nodes in the linked list, which is directly overwritten
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
//The passed in key already exists, overwrite the original value with the passed in value, and return the original value
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
//Record number of inserts
++modCount;
//Determine whether the number of saved nodes in the array is greater than the threshold value, and expand if it is greater than the threshold value
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}``````

3. resize method

``````final Node<K,V>[] resize() {
Node<K,V>[] oldTab = table;
int oldCap = (oldTab == null) ? 0 : oldTab.length;
int oldThr = threshold;
int newCap, newThr = 0;
//Existing capacity of old table
if (oldCap > 0) {
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
//Capacity expansion, capacity and threshold multiply by 2
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
}
//Initialization is also an integer multiple of the minimum 2 that is larger than the capacity value passed in. For example, the initial capacity of 15 is 16
else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr;
//If the initial value is not passed in, the default value will be taken. The capacity is 16 and the threshold value is 12
else {               // zero initial threshold signifies using defaults
newCap = DEFAULT_INITIAL_CAPACITY;
}
//If the capacity of new table is greater than int maximum or the capacity * load factor of new table is greater than int maximum, the capacity is int maximum
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) {
//Leave the original node reference empty
oldTab[j] = null;
//The current node is not a linked list node, and the new table subscript can be obtained by directly fetching the surplus with the new table capacity. Put the original node into the new table subscript
if (e.next == null)
newTab[e.hash & (newCap - 1)] = e;
//If it is a red black tree (to be improved)
else if (e instanceof TreeNode)
((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
else { // preserve order
Node<K,V> loHead = null, loTail = null;
Node<K,V> hiHead = null, hiTail = null;
Node<K,V> next;
//Using the hash value of the collision node and the capacity of the old table to do and (&), the original linked list can be divided into two linked lists and inserted into the new array
//For ex amp le, if the capacity of 3,11,19,27,35,43 and the old table is 8, the remainder is 3, but the result is 0,8,0,8,0,8
//You can put 3,19,35 in the position of the new table newTab[3], and 11,27,43 in the position of the new table newTab[11]
do {
next = e.next;
if ((e.hash & oldCap) == 0) {
if (loTail == null)
else
loTail.next = e;
loTail = e;
}
else {
if (hiTail == null)
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
}
if (hiTail != null) {
hiTail.next = null;
}
}
}
}
}
return newTab;
}``````

4. treeifyBin method

``````final void treeifyBin(Node<K,V>[] tab, int hash) {
int n, index; Node<K,V> e;
//Although the link list node is greater than 8, but the length of the tab is less than 64, expand the capacity first
if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
resize();
//Tree forming
else if ((e = tab[index = (n - 1) & hash]) != null) {
TreeNode<K,V> hd = null, tl = null;
//Turn all linked list nodes into tree nodes, and determine their prev and next relationships
do {
TreeNode<K,V> p = replacementTreeNode(e, null);
if (tl == null)
hd = p;
else {
p.prev = tl;
tl.next = p;
}
tl = p;
} while ((e = e.next) != null);
//The way to turn the real red black tree (to be improved))
if ((tab[index] = hd) != null)
hd.treeify(tab);
}
}``````

5. treeify method

``````   final void treeify(Node<K,V>[] tab) {
TreeNode<K,V> root = null;
for (TreeNode<K,V> x = this, next; x != null; x = next) {
next = (TreeNode<K,V>)x.next;
x.left = x.right = null;
//The previous method determines the relationship between the upstream and downstream tree nodes. Here, the first node is set as the root node
if (root == null) {
x.parent = null;
x.red = false;
root = x;
}
else {
K k = x.key;
int h = x.hash;
Class<?> kc = null;
//According to the hash value of each node, it is placed on the left or right node of the node whose leaf node is empty
//Put the big hash into the right node and the small hash into the left node to generate a simple tree
for (TreeNode<K,V> p = root;;) {
int dir, ph;
K pk = p.key;
if ((ph = p.hash) > h)
dir = -1;
else if (ph < h)
dir = 1;
else if ((kc == null &&
(kc = comparableClassFor(k)) == null) ||
(dir = compareComparables(kc, k, pk)) == 0)
dir = tieBreakOrder(k, pk);

TreeNode<K,V> xp = p;
if ((p = (dir <= 0) ? p.left : p.right) == null) {
x.parent = xp;
if (dir <= 0)
xp.left = x;
else
xp.right = x;
//Turn the tree into a red black tree (to be improved)
root = balanceInsertion(root, x);
break;
}
}
}
}
//Ensure that the first node of the array is the root node
moveRootToFront(tab, root);
}``````

Tags: Programming less

Posted on Sun, 03 May 2020 10:20:51 -0400 by quad