Hashmap principle summary 2 -- Put and Get process source code analysis summary

Hashmap principle summary 2

problem

  • Do you know what the process of the put element of HashMap is like
  • Do you know what the get process looks like
  • What other hash algorithms do you know
  • Let's talk about the implementation of String hashcode

It is recommended to read the source code for an analysis, and then check the way of listing points, review and summarize the content of the source code process, and deepen the memory!!
Conduct an analysis in annotated form

Put process source code analysis

JDK1.8 source code analysis

    /**
     * Implements Map.put and related methods.
     *
     * @param hash hash for key
     * @param key the key
     * @param value the value to put
     * @param onlyIfAbsent if true, don't change existing value
     * @param evict if false, the table is in creation mode.
     * @return previous value, or null if none
     */
    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 current table is empty or has no elements, the capacity will be expanded
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
            // Get the i corresponding to the current key and judge whether there is a node in the bucket
            // Note: index is n-1 & hash
        if ((p = tab[i = (n - 1) & hash]) == null)
        	// If not, create a new Node and put it into the bucket
            tab[i] = newNode(hash, key, value, null);
        else { // hash collision occurs
            Node<K,V> e; K k;
            // If the hash is the same, the key reference is the same or the key value is the same, record to e first
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            // If the first node is of red black tree type, the node addition method of red black tree type is used
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            // The first node is a linked list type
            else {
                // Traverse the nodes on the linked list
                for (int binCount = 0; ; ++binCount) {
                    // Find the end of the list
                    if ((e = p.next) == null) {
                        // Put the new node at the end first
                        p.next = newNode(hash, key, value, null);
                        // If the number of nodes exceeds the threshold, it will be transformed into a red black tree
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    // Judge whether the new node already exists on the linked list. If so, e the node information has been recorded
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            // Record nodes at the same location and overwrite them with value
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        // When the number of nodes + 1 is greater than the threshold, the capacity will be expanded
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

Note: jdk1 8. Use the tail insertion method of linked list, jdk1 Head insertion method was used before 8

PUT process is summarized again

Make a secondary summary by listing points
1. Calculate the hashcode value of the key
2. If the hash table is empty, call resize() to expand the capacity
3. Check for collision
3.1 if there is no collision, directly add the node into the bucket
3.2 in case of collision

  • If the first node has the same key address or the same content after equals, record e
  • For the red black tree type, the method of adding node to the red black tree type is adopted
  • For the linked list type, traverse the linked list
    • Traverse to the tail node of the linked list, perform tail interpolation, and judge whether the number of nodes exceeds the tree threshold. If it exceeds the threshold, it will turn into a red black tree
    • If the key address is the same or the content after equals is the same, record e
      4. e overwrite the original value
      5. Judge whether the new node is greater than the threshold (capacity * load_factor). If it exceeds the threshold, expand the capacity

Get process source code analysis

    // hash(key) method is used to calculate hashcode according to code
    public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }
    /**
     * Implements Map.get and related methods.
     *
     * @param hash hash for key
     * @param key the key
     * @return the node, or null if none
     */
    final Node<K,V> getNode(int hash, Object key) {
        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
        // Judge whether the table is empty
        // Find the index according to n-1 & hash 
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (first = tab[(n - 1) & hash]) != null) {
            // If the first node table[i] == key, it will be returned directly
            if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))
                return first;
            // If there are multiple nodes in the bucket
            if ((e = first.next) != null) {
                // If it is a red black tree, the traversal method of the tree is used
                if (first instanceof TreeNode)
                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
                do {
                    // If it is a linked list, it will traverse and distinguish different nodes by judging the hash value
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

The Get process is summarized again

Make a secondary summary by listing points
1. Get the hash value according to the key value
2. Get the subscript corresponding to the key according to the hash
3. Judge whether the table is empty
3.1 if it is empty, null will be returned
3.2 if not empty

  • If the first node is the same, return node
  • It is a red black tree type, which adopts a convenient way of tree search
  • For the linked list type, loop through and return node if found, null if not found

After personal summary
Reference articles

1.https://www.bilibili.com/read/cv5517205/
2.https://zhuanlan.zhihu.com/p/353846426
3.https://blog.csdn.net/u011277123/article/details/80467673 (put details)
4.https://blog.csdn.net/m0_37550986/article/details/115833221 (get details)

Keywords: Java linked list

Added by ybinds on Wed, 02 Feb 2022 02:44:56 +0200