HashMap

72 阅读2分钟

基本原理

HashMap在JDK1.8中采用数组+链表+红黑树进行存储,通过计算key的hashCode,利用hashCode通过hash方法计算出桶下标,再判断HashMap中是否存在该键值对,存在:判断新键值对与该桶第一个节点是否相同,相同,判断 onlyIfAbsent 表示是否仅在 oldValue 为 null 的情况下更新键值对的值 不存在:判断是否是红黑树节点,是:按照红黑树插入节点方式进行插入,不是:插入到链表最后一个位置,并且判断是否大于或者等于链表转换红黑树的阈值,若是则进行红黑树转化,最后判断键值对总数是否到达阈值,是,进行扩容

image.png

构造方法

共有4种构造方法
无参构造方法,最常用

public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}

第二种、第三种,设置了一些变量

/** 构造方法 2 */
public HashMap(int initialCapacity) {
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
}

/** 构造方法 3 */
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);
}

第四种拷贝一份Map,不常用

/** 构造方法 4 */
public HashMap(Map<? extends K, ? extends V> m) {
    this.loadFactor = DEFAULT_LOAD_FACTOR;
    putMapEntries(m, false);
}

参数说明

参数说明
initialCapacityHashMap初始容量
loadFactor加载因子
thresold阈值

此处提问的问题

  1. 数组长度为什么是2的幂次方

    加快计算以及减少哈希冲突 确定数组下标,位运算比取模运算快;可以让高位、底位都参加到数组下标计算中,增大hash的复杂度

  2. 如何扩容

    确定数组容量大小合适:HashMap之tableSizeFor方法图解 - 掘金 (juejin.cn) image.png resize:

       resize分为3种情况:
           1.数组不为空
           2.数组为空,但设置了数组初始值
           3.数组为空,调用无参构造方法
       1.数组大小、阈值直接扩容为原来的22.newCap取初始容量,若初始容量不合理,使用tableSizeFor设为2的幂次方
       3.设置为默认大小
       再对情况1做数值迁移
           旧元素桶下标变为:下标值不变||下标值变为原来的2倍
           其实很容易理解,初始化和 (16 - 1)做与运算时,只有低 4 位的 hash 是有意义的,
           是扩容的时候,和 (32 -1 )做与运算时,低 5 位也参与了运算,所以低 5 位的值决定了
           rehash 后新的 index 的值。如果低 5 位为 0index 值不变,如果低 5 位为1,则 
           index 改变,并且在原先基础上加了 24 次方,即 16

    Java集合—HashMap之resize方法 - 掘金 (juejin.cn)

  3. 头插法、尾插法

  4. 如何插入 image.png

  5. 系类问题:hashmap头插法和尾插法区别_一个跟面试官扯皮半个小时的HashMap(看这一篇就足够了) - 掘金 (juejin.cn)