一文读懂 HashMap 核心原理

在 Java 开发中,HashMap 是使用频率极高的集合类,理解其底层原理对性能优化和问题排查至关重要。接下来从数据结构、容量机制、操作流程等多个维度,深入剖析 HashMap 的运行机制。

博主总结

一、数据结构:数组 + 链表 + 红黑树

HashMap 采用数组 + 链表 + 红黑树的复合结构。数组作为主体存储数据,每个数组元素称为一个 “桶”;当发生哈希冲突时,冲突元素通过链表形式存储在对应桶中。当链表长度超过 8 且数组长度大于 64 时,链表会转换为红黑树,将查询时间复杂度从链表的 O (n) 优化至红黑树的 O (logn),大幅提升查询效率。

二、容量机制:初始容量与扩容

  • 初始容量:HashMap 默认初始容量为 16,若初始化时传入非 2 的幂次方值(如 17),会自动调整为大于等于该值的最小 2 的幂次方(即 32)。
  • 扩容机制:当键值对数量超过 ** 容量 × 负载因子(默认 0.75)** 时触发扩容。扩容时,创建容量为原来 2 倍的新数组,并将旧数组元素重新分配到新数组。JDK 8 采用尾插法,通过(e.hash & oldCap) == 0判断元素位置,避免重新计算哈希值,提高扩容性能。

三、核心操作流程

put 流程

  1. 哈希寻址:通过哈希函数计算键的哈希值,并与数组长度 - 1 进行按位与运算,确定元素所在桶的索引。
  1. 判断桶状态:若桶为空,直接插入;若不为空,判断是链表还是红黑树。
  1. 处理冲突:链表结构按顺序遍历插入,红黑树按树结构插入;若键已存在,则覆盖旧值。
  1. 扩容判断:插入后检查键值对数量是否超过阈值,超过则触发扩容。

get 流程

  1. 通过哈希值定位数组索引,找到对应桶。
  1. 检查桶中第一个节点,若匹配则直接返回;否则根据节点类型遍历链表或红黑树查找,找到则返回结果,未找到返回 null。

四、哈希冲突处理与优化

减少哈希冲突

  • 哈希值计算:通过高位与低位异或运算,让哈希值更均匀分布。
  • 索引计算:利用h & (n - 1)(n 为数组长度且是 2 的幂次方)按位与运算替代取模运算,提高计算效率。

解决哈希冲突方法

  • 拉链法:HashMap 采用的方法,用链表处理冲突,链表过长时转换为红黑树,扩容时树元素个数小于 6 则退化为链表。
  • 再哈希法:准备多套哈希算法,冲突时切换算法直至找到空槽,对算法设计要求高。
  • 开放地址法:包括线性探测(顺序查找空槽)、二次探测(按平方步长查找)、双重哈希(使用备用哈希函数)。

五、线程安全性对比

  • HashMap:线程不安全,多线程环境下可能出现数据覆盖、死循环等问题。
  • Hashtable:通过synchronized修饰方法实现线程安全,但锁粒度大,性能差。
  • ConcurrentHashMap:Java 8 后采用CAS 操作 + synchronized 锁,写操作通过 CAS 插入节点,冲突时对链表 / 红黑头结点加锁;读操作大多无锁,通过volatile保证可见性,性能更优,推荐使用。

完结。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值