Hashmap source code analysis (jdk1.8) and interview questions

Hashmap source code analysis

import java.io.IOException;
import java.io.InvalidObjectException;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import sun.misc.SharedSecrets;
  • Hash table is based on the implementation of the Map interface. Hashmap provides all optional map operations and allows keys and values ​​to be null (except for unsynchronized and allowing null values, HashMap is roughly equivalent to Hashtable) Hashmap traversal order is indeterminate.
  • An instance of Hashmap has two parameters that affect its performance: initial capacity and load factor, capacity is the number of buckets in the hash table, initial capacity is the capacity of the hash table when it was created, and load factor is the hash table as its capacity automatically increases A measure of how full it was before.
    When the number of entities in the hash table exceeds the load factor * capacity, the hash table needs to be rehashed (ie, the internal data structure is rebuilt), and the hash table will expand to about twice the number of buckets.
  • The basic rule is that the default load factor is 0.75, which forms a good compromise between time and space costs.
  • The number of entries required in the map and its load factor should be taken into account when setting the initial capacity in order to minimize the number of rehash operations. If the initial capacity is greater than the maximum number of entries divided by the load factor, no rehash operation will occur.
  • If there are many maps to be stored in the HashMap instance, using a sufficiently large initial capacity when creating the hash table will be more efficient than performing automatic rehashing as needed to increase the size of the table.
  • Hashmap is thread-unsafe. If multiple threads access a hash map at the same time, and at least one thread modifies the map structure, synchronization operations must be performed externally. (Structural modification is the operation of adding or removing one or more mappings, just changing the key-related value of an already existing instance is not a structural modification.)
  • Fast-fail event: When multiple threads operate the Collection, if one of the threads traverses the collection through the iterator, the content of the collection is changed by other threads; ConcurrentModificationException will be thrown. So iterators fail fast when there are concurrent modifications. The fail-fast behavior of iterators cannot be guaranteed, and in general, it is impossible to make any firm guarantees in the presence of unsynchronized concurrent modifications. Fail-fast iterators do their best to throw ConcurrentModificationException. Therefore, it is wrong to write programs that depend on this exception, and it is right: the fail-fast behavior of iterators should only be used to detect program errors.

    public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {
    private static final long serialVersionUID = 362498820763181265L;
    //默认初始容量是16,必须是2的幂(为什么?后面介绍)
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
    //最大容量,当使用带参构造函数指定初始容量时使用,避免指定的初始容量大于最大容量
    static final int MAXIMUM_CAPACITY = 1 << 30;
    //默认加载因子
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    //桶的技术阈值,当添加元素时桶中的数量至少有这些时应该转换为树,而不是继续使用链表
    static final int TREEIFY_THRESHOLD = 8;
    static final int UNTREEIFY_THRESHOLD = 6;
    static final int MIN_TREEIFY_CAPACITY = 64;
    • Definition of Hash Bucket Node
 static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public final K getKey()        { return key; }
        public final V getValue()      { return value; }
        public final String toString() { return key + "=" + value; }

        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public final boolean equals(Object o) {
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
    }
  • Calculate key.hashCode(), the high-order operation
    h = key.hashCode() is 32 bits, and the high-order 16 of these 32-bits are located in the low-order 16 bits for XOR operation, and both high and low bits are involved in the operation. Binary operations are more efficient than modulo operations.
static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
  • Analysis of the parameterized constructor of Hashmap:
    If the initial capacity is less than 0 or the load factor is less than or equal to 0, an IllegalArgumentException will be
    thrown . When the initial capacity is greater than the maximum capacity, the initial capacity is set to the maximum capacity.
public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }

Continually updated. . . . . . . .

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324607367&siteId=291194637