砍材农夫砍材农夫
  • 微信记账小程序
  • java
  • redis
  • mysql
  • 场景类
  • 框架类
  • vuepress搭建
  • hexo搭建
  • 云图
  • 常用工具

    • git
    • gradle
    • Zadig
    • it-tools
    • 开源推荐
    • curl
  • 大前端

    • nodejs
    • npm
    • webpack
    • 微信
    • 正则
    • uniapp
  • java

    • java基础
    • jdk体系
    • jvm
    • spring
    • spring_cloud
    • spring_boot
    • 分库分表
    • zookeeper
  • python

    • python基础
    • python高级
    • python框架
  • 算法

    • 算法
  • 网关

    • spring_cloud_gateway
    • openresty
  • 高可用

    • 秒杀
    • 分布式
    • 缓存一致
  • MQ

    • MQ
    • rabbitMQ
    • rocketMQ
    • kafka
  • 其它

    • 设计模式
    • 领域驱动(ddd)
  • 关系型数据库

    • mysql5.0
    • mysql8.0
  • 非关系型数据库

    • redis
    • mongoDB
  • 分布式/其他

    • ShardingSphere
    • 区块链
  • 向量数据库

    • M3E
    • OPEN AI
  • Jmeter
  • fiddler
  • wireshark
  • AI入门
  • AI大模型
  • AI插件
  • AI集成框架
  • 相关算法
  • AI训练师
  • 量化交易
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 相关运营
  • docker
  • k8s
  • devops
  • nginx
  • 元宇宙
  • 区块链
  • 物联网
  • linux
  • webrtc
  • web3.0
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 中考
  • 投资
  • 保险
  • 思
  • 微信记账小程序
  • java
  • redis
  • mysql
  • 场景类
  • 框架类
  • vuepress搭建
  • hexo搭建
  • 云图
  • 常用工具

    • git
    • gradle
    • Zadig
    • it-tools
    • 开源推荐
    • curl
  • 大前端

    • nodejs
    • npm
    • webpack
    • 微信
    • 正则
    • uniapp
  • java

    • java基础
    • jdk体系
    • jvm
    • spring
    • spring_cloud
    • spring_boot
    • 分库分表
    • zookeeper
  • python

    • python基础
    • python高级
    • python框架
  • 算法

    • 算法
  • 网关

    • spring_cloud_gateway
    • openresty
  • 高可用

    • 秒杀
    • 分布式
    • 缓存一致
  • MQ

    • MQ
    • rabbitMQ
    • rocketMQ
    • kafka
  • 其它

    • 设计模式
    • 领域驱动(ddd)
  • 关系型数据库

    • mysql5.0
    • mysql8.0
  • 非关系型数据库

    • redis
    • mongoDB
  • 分布式/其他

    • ShardingSphere
    • 区块链
  • 向量数据库

    • M3E
    • OPEN AI
  • Jmeter
  • fiddler
  • wireshark
  • AI入门
  • AI大模型
  • AI插件
  • AI集成框架
  • 相关算法
  • AI训练师
  • 量化交易
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 相关运营
  • docker
  • k8s
  • devops
  • nginx
  • 元宇宙
  • 区块链
  • 物联网
  • linux
  • webrtc
  • web3.0
  • gitee
  • github
  • infoq
  • osc
  • 砍材工具
  • 关于
  • 中考
  • 投资
  • 保险
  • 思
  • 首页
  • 基础

    • map循环
    • 委托
    • 泛型
    • 线程池
    • String 为什么不可变?面试必问
    • Java 异常处理最佳实践,别再乱用 try-catch
    • 为什么禁止在for循环里使用+拼接字符串
    • HashMap底层原理面试必背精简版
    • HashSet、LinkedHashSet、TreeSet 区别与使用场景
    • Java创建线程的3种方式简单易懂
    • 如何使用 jstack 排查死锁
  • HashMap 底层原理(面试精简版)
    • 1. 底层数据结构
    • 2. 核心常量
    • 3. Put 流程(JDK 1.8)
    • 4. 扩容机制
    • 5. 线程安全性
    • 6. 关键知识点
    • 7. JDK 1.7 vs 1.8 区别

HashMap 底层原理(面试精简版)

1. 底层数据结构

  • JDK 1.7:数组 + 链表
  • JDK 1.8+:数组 + 链表 + 红黑树
    • 链表长度 > 8 且数组长度 ≥ 64 时,链表转为红黑树
    • 红黑树节点数 < 6 时,退化为链表

2. 核心常量

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 默认初始容量 16
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;         // 最小树化容量

3. Put 流程(JDK 1.8)

  1. 计算 hash(key):(key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)(扰动函数,高低位异或)
  2. 若数组为空,触发 resize() 初始化
  3. 计算索引:(n - 1) & hash,若该位置为空,直接插入
  4. 若不为空:
    • 检查 key 是否相等,相等则覆盖
    • 若为红黑树节点,调用 putTreeVal
    • 若为链表,遍历到尾插(JDK 1.7 头插,1.8 改为尾插),同时计数,超过 8 则转红黑树
  5. 插入后判断 size > threshold,是则扩容

4. 扩容机制

  • 触发条件:size >= threshold(threshold = capacity * loadFactor)
  • 扩容大小:新容量 = 旧容量 << 1(翻倍)
  • 重哈希:节点重新计算索引,JDK 1.8 优化:
    • 节点在原位置或 原位置 + 旧容量,通过 (e.hash & oldCap) == 0 判断
    • 无需重新计算 hash,减少开销

5. 线程安全性

  • HashMap 非线程安全
  • 并发场景下可能产生:
    • JDK 1.7 头插法导致死循环(多线程扩容时)
    • 数据丢失、size 不准确
  • 替代方案:ConcurrentHashMap、Collections.synchronizedMap

6. 关键知识点

问题答案
为什么容量是 2 的幂方便取模运算 (n - 1) & hash,保证均匀分布
负载因子为什么 0.75时间与空间平衡的折中
为什么引入红黑树防止链表过长导致查询 O(n) 退化为 O(log n)
null key 存在位置固定存放在数组 0 号桶

7. JDK 1.7 vs 1.8 区别

对比项JDK 1.7JDK 1.8
数据结构数组 + 链表数组 + 链表 + 红黑树
插入方式头插法尾插法
扩容重哈希重新计算每个 hash优化为原位置或原位置+旧容量
扰动函数多次异或一次异或(高16位与低16位异或)

面试常问:“HashMap 的 get 流程?” → 计算 hash → 定位桶 → 遍历链表/红黑树,用 equals() 比较 key 返回 value。

最近更新: 2026/3/28 17:49
Contributors: kcnf
Prev
为什么禁止在for循环里使用+拼接字符串
Next
HashSet、LinkedHashSet、TreeSet 区别与使用场景