当前位置: 首页 > news >正文

HashMap底层实现原理与核心设计解析

一、底层数据结构

HashMap基于哈希表实现,其底层结构在不同Java版本中有所优化:

  • Java 8之前:采用数组 + 链表的组合结构
  • Java 8及之后:升级为数组 + 链表 + 红黑树的复合结构

其中,链表与红黑树的转换机制如下:

  • 当链表长度超过8,且数组长度≥64时,链表转为红黑树(红黑树查询复杂度为O(log₂N),远优于链表的O(N))
  • 当红黑树节点数量减少至6以下时,自动退化为链表(节点较少时,链表维护成本更低)

二、元素插入流程

  1. 计算索引:通过键的hashCode()方法获取哈希值,经二次哈希处理后计算数组索引
  2. 判断插入位置
    • 若索引位置为空,直接插入键值对
    • 若索引位置不为空,需进一步判断:
      • 若当前key与已有key相同(hash值一致且equals()返回true),直接覆盖原有值
      • 若key不同,根据当前结构类型处理:
        • 红黑树结构:执行红黑树的节点添加逻辑
        • 链表结构:遍历链表检查是否存在相同key
          • 存在相同key:覆盖对应值
          • 不存在相同key:采用尾插法插入新节点,插入后若链表长度超过8,触发红黑树转换

三、扩容机制

当插入元素后,若负载因子(元素数量/数组容量)超过0.75,触发扩容操作:

  • 扩容后数组容量变为原来的2倍(保证容量始终为2的n次方)
  • 所有元素重新计算索引并迁移至新数组(重新哈希)

四、核心设计逻辑解析

  1. 数组长度为何是2的n次方?

    • 便于通过(n-1) & hash高效计算数组索引(等价于取模运算但性能更优)
    • 保证哈希值的每一位都能参与索引计算,使元素分布更均匀
    • 支持扩容时的高效重哈希(新索引仅为原索引或原索引+旧容量)
  2. 负载因子默认0.75的原因?

    • 平衡时间效率与空间效率:过低会导致空间浪费,过高会增加哈希冲突概率
  3. 为何按2倍扩容?

    • 确保扩容后数组长度仍为2的n次方,维持索引计算与重哈希的高效性

通过以上设计,HashMap在查询性能、空间利用率和哈希冲突处理之间取得了精妙平衡,成为Java中最常用的键值对存储容器之一。

http://www.dtcms.com/a/297931.html

相关文章:

  • AI同传领域,字节跳动与科大讯飞激战进行时
  • 【Linux系统】基础IO(下)
  • 深度学习篇---图像数据采集
  • classgraph:Java轻量级类和包扫描器
  • 深度学习篇---深度学习中的卡尔曼滤波
  • Vmware VSAN主机停机维护流程
  • RAG、Function Call、MCP技术笔记
  • Java中给List<String>去重的4种方式
  • 数据结构:对角矩阵(Diagonal Matrix)
  • Android UI 组件系列(八):ListView 基础用法与适配器详解
  • python语法笔记
  • 《剑指offer》-数据结构篇-链表
  • GDB调试命令学习
  • spring boot项目使用Spring Security加密
  • k8s开启审计日志
  • 【SSL证书校验问题】通过 monkey-patch 关掉 SSL 证书校验
  • Fluent遇上AI:深度学习重塑计算流体动力学的未来
  • 【记录】C++生产者 / 消费者 案例
  • 刷题日记0725
  • 篇五 网络通信硬件之PHY,MAC, RJ45
  • PytorchLightning最佳实践基础篇
  • 谷歌母公司Alphabet发布超预期业绩,提高全年资本支出至850亿美元
  • 从 Elastic 到 ClickHouse:日志系统性能与成本优化之路
  • 【大模型实战】提示工程(Prompt Engineering)
  • 优秀案例:基于python django的智能家居销售数据采集和分析系统设计与实现,使用混合推荐算法和LSTM算法情感分析
  • 九联UNT413AS_晶晨S905L3S芯片_2+8G_安卓9.0_线刷固件包
  • 短剧小程序系统开发:构建影视娱乐生态新格局
  • Spring Boot License 认证系统
  • C#(数据类型)
  • k8s的存储之secerts