Bootstrap

HashMap的底层实现原理是什么?JDK 1.8之后有什么优化?

  1. 数据结构:数组+链表+红黑树(jdk1.8引入)

    • 默认使用数组(Node<K,V>[] table)存储元素,每个数组元素称为桶

    • 哈希冲突时,会将冲突的key-value放入一个桶内,同一桶内元素以链表形式存在(拉链法)

    • JDK 1.8 优化:当链表长度超过阈值(默认 8)且数组长度 ≥ 64 时,链表转换为红黑树,以降低查询时间复杂度(从 O(n) 优化为 O(log n))

  2. 哈希函数

    • 通过 hash(key) 计算键的哈希值,决定键值对在数组中的位置。

    • JDK 1.8 优化:哈希计算简化为一次位运算(高位参与异或),减少哈希碰撞概率

  3. 冲突解决

    • 拉链法:冲突的键值对以链表或红黑树形式存储在同一个桶中

  4. 扩容机制

    • 触发条件:当元素数量超过阈值(容量 × 负载因子,默认负载因子 0.75)。

    • 扩容过程:数组大小翻倍(2^n),并重新计算所有元素的位置(rehash)。

    • JDK 1.8 优化:通过高位判断元素新位置,避免重新计算哈希值:

      • 新位置 = 原位置 或 原位置 + 旧容量。

JDK 1.8 的主要优化

  1. 红黑树引入

    • 目的:解决链表过长导致的查询效率低下问题。

    • 阈值:链表长度 ≥ 8 且数组长度 ≥ 64 时转红黑树;红黑树节点数 ≤ 6 时退化为链表。

  2. 扩容效率提升

    • 高位掩码法:通过 (e.hash & oldCap) == 0 判断元素是否需要移动到新位置(原索引 + oldCap),避免重新计算哈希值。

  3. 尾插法替代头插法

    • JDK 1.7 问题:多线程扩容时头插法可能导致环形链表,引发死循环。

    • JDK 1.8 解决:改用尾插法,避免环形链表(但 HashMap 仍非线程安全)。

  4. 哈希函数简化

    • 通过一次位运算(高位异或)替代多次扰动计算,平衡性能与哈希分布

拉链法(Separate Chaining)详解

拉链法是解决哈希表(Hash Table)哈希冲突的一种经典方法。其核心思想是:当多个键(Key)经过哈希函数计算后得到相同的哈希值(即落在同一个“桶”中)时,将这些键值对以链表形式存储在同一个桶内

;