HashMap collection put function source code reading record

Before reading the source code of the put function, first look at several variables that will be used

/**
 * 用于记录HashMap集合中增、删、改的次数
 * 该值会在初始化迭代器时存储在一个局部变量expectedModCount中
 * 由于HashMap不是线程安全的,因此在使用迭代器时,如果有其它线程修改了map,会造成modCount的值与expectedModCount不一至,将会抛出ConcurrentModificationException异常
 */
transient int modCount;

/**
 * 用于表示key为空的条目
 */
transient HashMapEntry<K, V> entryForNullKey;

/**
 * HashMap集合大小的阈值
 */
private transient int threshold;

First look at the most commonly used put(K key, V value) function in the Map collection

/**
 * Maps the specified key to the specified value.
 *
 * @param key
 *            the key.
 * @param value
 *            the value.
 * @return the value of any previous mapping with the specified key or
 *         {@code null} if there was no such mapping.
 */
@Override public V put(K key, V value) {
    if (key == null) {
        return putValueForNullKey(value);
    }
    // 计算key的hash值
    int hash = Collections.secondaryHash(key);
    HashMapEntry<K, V>[] tab = table;
    // 根据hash值计算存储的位置
    int index = hash & (tab.length - 1);
    
    // 循环偏历entry数组,判断key对应的entry是否存在,如果对应的entry已经存在,则直接将旧的entry.value修改为新的value,并且返回旧的value
    for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
        // 判断hash、key值是否完全都相同
        if (e.hash == hash && key.equals(e.key)) {
            preModify(e);
            V oldValue = e.value;
            e.value = value;
            return oldValue;
        }
    }

    // No entry for (non-null) key is present; create one
    modCount++; // 记录修改次数
    // 判断当前map集合的长度是否超出阈值
    if (size++ > threshold) {
        // 扩容,并且重新生成Hash表
        tab = doubleCapacity();
        // 根据新生成的hash表重新计算存储的位置
        index = hash & (tab.length - 1);
    }
    // 创建对应的entry数据并保存在对应的存储位置
    addNewEntry(key, value, hash, index);
    return null;
}

When the stored key value is null, putValueForNullKey(V value) will be called. When the key value is not null, see the comments. The code of the putValueForNullKey function is as follows

private V putValueForNullKey(V value) {
    HashMapEntry<K, V> entry = entryForNullKey;
    if (entry == null) {
        addNewEntryForNullKey(value);
        size++;
        modCount++;
        return null;
    } else {
        preModify(entry);
        V oldValue = entry.value;
        entry.value = value;
        return oldValue;
    }
}

It is judged here that when the entry is empty, the addNewEntryForNullKey() function will be called first, and the function will be called to create a HashMapEntry object, and the newly created HashMapEntry is referenced by entryForNullKey.
When the entry is not empty, indicating that there is a reference to entryForNullKey before, the old value is directly replaced with the new value, and the old value is returned.

/**
 * Creates a new entry for the null key, and the given value and
 * inserts it into the hash table. This method is called by put
 * (and indirectly, putAll), and overridden by LinkedHashMap.
 */
void addNewEntryForNullKey(V value) {
    entryForNullKey = new HashMapEntry<K, V>(null, value, 0, null);
}

Guess you like

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