简介

一般集合和map的底层原理实现可能会被面试官问到.


参数

  1. DEFAULT_LOAD_FACTOR

static final float DEFAULT_LOAD_FACTOR = 0.75f; 负载因子 2. 门限

// (The javadoc description is true upon serialization.
    // Additionally, if the table array has not been allocated, this
    // field holds the initial array capacity, or zero signifying
    // DEFAULT_INITIAL_CAPACITY.)
    int threshold;

门限计算公式
threshold = 数组长度 * 负载因子;

size

size 是HashMap中实习存在的键值对数量

/**
     * The number of key-value mappings contained in this map.
     */
    transient int size;

modCount

hashmap 发生结构变化的次数.

/**
     * The number of times this HashMap has been structurally modified
     * Structural modifications are those that change the number of mappings in
     * the HashMap or otherwise modify its internal structure (e.g.,
     * rehash).  This field is used to make iterators on Collection-views of
     * the HashMap fail-fast.  (See ConcurrentModificationException).
     */
    transient int modCount;

INITIAL_CAPACITY

/**
     * The default initial capacity - MUST be a power of two.
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

初始化容量为16.

为什么选用2的幂次

因为 比如16: 1 0000
16 - 1 = 0 1111
使用这个对hashcode产生的书进行与操作 可以得到16以内的数

hashCode 如何将高位也进行与操作 减少冲突

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

hashmap 1.7 采用头插法, 1.8 采用尾插法 为什么

因为每次都要查询链表是不是8个, 所以查询结束直接尾插法,效率较高

HashMap 发生死循环的一个重要原因是 JDK 1.7 时链表的插入是首部倒序插入的,而 JDK 1.8 时已经变成了尾部插入,有人把这个死循环的问题反馈给了 Sun 公司,但它们认为这不是一个问题,因为 HashMap 本身就是非线程安全的,如果要在多线程使用建议使用 ConcurrentHashMap 替代 HashMap,但面试中这个问题被问的频率比较高,所以在这里就特殊说明一下。

java 设置hashmap指定的值_链表

1.8 每次链表长度到8都会扩容吗

不会哦. 有一个64的参数, 如果没有达到64的话, 会先进行扩容.

TIPS

java 设置hashmap指定的值_链表_02

  • hashmap 采用了数组 + 链表 + 红黑树 jdk.18的存储结构.
  • hashmap 数组部分称为哈希桶. 当链表长度大于等于8时, 链表数据将以红黑树的形式进行存储, 当长度降到6时, 转成链表.
  • 链表的时间复杂度为O(n)
  • 红黑树的时间复杂度为O(log n)
  • 当插入的对象大小超过临界值时, HashMap将新建一个桶数组并重新赋值. 此时, 桶数组是原来的两倍, 门限也是原来的两倍. 然后从新赋值