Java中的HashMap实现原理深入理解

 更新时间:2025年12月11日 09:33:45   作者:im_winter185  
HashMap是一种非常常见和实用的数据结构,它被广泛应用于Java编程中,这篇文章主要介绍了Java中HashMap实现原理的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

一、前言

在 Java 开发中,HashMap 是我们最常用的集合类之一。无论是缓存、配置存储,还是数据传输,HashMap 都扮演着重要角色。但你是否真正了解它的底层实现?为什么它查找这么快?什么时候会退化成链表?JDK1.8 之后又有哪些优化?

本文将带你深入理解 HashMap 的实现原理,帮助你从“会用”到“懂原理”。

二、HashMap 的基本结构

1. 底层数据结构(JDK 1.8 之前 vs 之后)

版本数据结构
JDK 1.7数组 + 链表
JDK 1.8数组 + 链表 + 红黑树

解释:

  • 数组HashMap 的主干是一个 Node<K,V>[] table,每个元素是一个桶(bucket)。

  • 链表:当发生哈希冲突时,多个键值对会以链表形式存储在同一个桶中。

  • 红黑树:当链表长度超过 8 且数组长度大于 64 时,链表会转为红黑树,提升查询效率。

三、核心源码解析

1. 构造函数与初始容量

public HashMap(int initialCapacity, float loadFactor) {
    this.loadFactor = loadFactor;
    this.threshold = tableSizeFor(initialCapacity);
}
  • initialCapacity:初始容量,必须是 2 的幂。

  • loadFactor:负载因子,默认是 0.75,用于控制扩容时机。

2. put 方法流程

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

步骤如下:

  1. 计算 key 的 hash 值(hash(key)

  2. 定位桶位置((n - 1) & hash

  3. 如果桶为空,直接插入

  4. 如果桶不为空,遍历链表或红黑树

  5. 如果 key 已存在,覆盖 value

  6. 如果插入后长度超过阈值,触发扩容或树化

3. 哈希函数设计

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

目的: 减少哈希冲突,让高位也参与运算,提升分布均匀性。

四、扩容机制(resize)

当元素个数超过 threshold = capacity * loadFactor 时,会触发扩容:

  • 容量翻倍(newCap = oldCap << 1

  • 重新计算每个元素的位置(要么在原位置,要么在原位置 + oldCap)

优化点: JDK 1.8 中不需要重新计算 hash,只需看新增的那一位是 0 还是 1。

五、线程安全问题

⚠️ HashMap 是线程不安全的!

问题表现:

  • 多线程 put 可能导致链表成环(JDK 1.7)

  • 数据丢失、覆盖等问题

解决方案:

方式说明
Collections.synchronizedMap()包装器,性能差
ConcurrentHashMap推荐,分段锁/CAS 实现,线程安全且高效

六、面试高频问题总结

问题简答
HashMap 的底层结构?数组 + 链表 + 红黑树(JDK 1.8)
为什么容量必须是 2 的幂?位运算效率高,hash & (n-1) 替代取模
什么时候转红黑树?链表长度 > 8 且数组长度 > 64
为什么加载因子是 0.75?平衡空间与时间效率
如何线程安全地使用 Map?使用 ConcurrentHashMap

七、总结思维导图(文字版)

HashMap
├── 结构:数组 + 链表 + 红黑树
├── 核心方法:put、get、resize、hash
├── 优化:树化、扩容、hash 散列
├── 线程安全:ConcurrentHashMap
└── 面试点:容量、负载因子、冲突处理、树化条件

八、附录:手写一个简易 HashMap(练习)

public class MyHashMap<K, V> {
    private Node<K, V>[] table;
    private int size;

    static class Node<K, V> {
        final int hash;
        final K key;
        V value;
        Node<K, V> next;

        Node(int hash, K key, V value, Node<K, V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }
    }

    public void put(K key, V value) {
        // 简化版,省略扩容、树化等逻辑
    }

    public V get(K key) {
        // 简化版
        return null;
    }
}

九、结语

理解 HashMap 的底层实现,不仅能帮助你在面试中脱颖而出,更能在实际开发中避免踩坑。希望本文能为你打下坚实的基础。

如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、评论!
后续我还会更新《ConcurrentHashMap 源码解析》《Java 集合框架全景图》等内容,记得关注我哦!

十、参考资料

到此这篇关于Java中的HashMap实现原理的文章就介绍到这了,更多相关Java HashMap实现原理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中for循环内修改集合的常见陷阱与最佳实践

    Java中for循环内修改集合的常见陷阱与最佳实践

    在Java编程中,for循环是遍历集合(如List、Set)的常用方式,本文主要介绍了Java在for循环内修改集合的常见陷阱与最佳实践,希望对大家有所帮助
    2025-06-06
  • springboot hazelcast缓存中间件的实例代码

    springboot hazelcast缓存中间件的实例代码

    这篇文章主要介绍了springboot hazelcast缓存中间件的实例代码,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-08-08
  • SpringBoot常用注解,thymeleaf,数据提交的实现

    SpringBoot常用注解,thymeleaf,数据提交的实现

    SpringBoot简化了微服务配置,提供快速启动和内嵌容器化web项目,常用注解包括@Component、@RestController等,Thymeleaf为前端页面渲染提供支持,数据提交时需使用@RequestBody注解
    2026-01-01
  • 详解springboot整合mongodb

    详解springboot整合mongodb

    本篇文章主要介绍了详解springboot整合mongodb,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • 并发编程之Java内存模型锁的内存语义

    并发编程之Java内存模型锁的内存语义

    这篇文章主要介绍了并发编程之Java内存模型锁的内存语义,锁的作用是让临界区互斥执行,本文只要围绕锁的内存语义展开全文内容,需要的小伙伴可以参考一下
    2021-11-11
  • Java 运算符详情

    Java 运算符详情

    这篇文章主要介绍了Java 运算符,Java 中的运算符与 C 语言基本一致。下面文章就围绕Java 中的运算符的相关资料展开内容,需要的朋友可以参考一下
    2021-11-11
  • Spring Bean后处理器详细介绍

    Spring Bean后处理器详细介绍

    Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理。可以在​Spring容器通过插入一个或多个BeanPostProcessor的实现来完成实例化,配置和初始化一个​bean​之后实现一些自定义逻辑回调方法
    2023-01-01
  • springboot配置redis过程详解

    springboot配置redis过程详解

    这篇文章主要介绍了springboot配置redis过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • JVM类加载器之ClassLoader的使用详解

    JVM类加载器之ClassLoader的使用详解

    类加载器负责读取Java字节代码,并转换成java.lang.Class类的一个实例的代码模块。本文主要和大家聊聊JVM类加载器ClassLoader的使用,需要的可以了解一下
    2022-10-10
  • Java轻松掌握面向对象的三大特性封装与继承和多态

    Java轻松掌握面向对象的三大特性封装与继承和多态

    本文主要讲述的是面向对象的三大特性:封装,继承,多态,内容含括从封装到继承再到多态的所有重点内容以及使用细节和注意事项,内容有点长,请大家耐心看完
    2022-05-05

最新评论