0

0

在Java里HashMap的put方法是如何执行的_JavaMap存储机制说明

P粉602998670

P粉602998670

发布时间:2026-02-09 09:19:07

|

617人浏览过

|

来源于php中文网

原创

Java 8中HashMap.put()先调用key.hashCode()并执行扰动运算(h = key.hashCode()) ^ (h >>> 16),null键哈希值固定为0;下标通过hash & (table.length - 1)计算,要求table.length为2的幂;冲突时先比哈希再equals,链表长度≥8且容量≥64时树化,扩容触发条件是size > threshold,新容量翻倍,rehash时节点仅需判断高位bit决定落位原下标或原下标+旧容量。

在java里hashmap的put方法是如何执行的_javamap存储机制说明

put方法执行时如何计算key的哈希值

Java 8 中 HashMap.put() 第一步不是直接查表,而是调用 key.hashCode(),再对结果做一次扰动运算:(h = key.hashCode()) ^ (h >>> 16)。这个异或操作是为了让高位也参与下标计算,缓解低位冲突——尤其当数组长度是2的幂次(如默认16)时,只用低位容易导致大量key映射到同一桶。

注意:如果key为null,哈希值固定为0,不调用hashCode(),也不会抛NullPointerException

哈希值怎么变成数组下标

下标不是直接取模,而是用位运算:index = hash & (table.length - 1)。前提是table.length必须是2的幂(扩容时强制保证),这样位运算等价于取余,但快得多。

常见误区:
- 不是hash % table.length,所以负哈希值不会出错(位运算是无符号逻辑)
- 如果你手动传入非2的幂长度(比如通过反射改table),下标计算会错乱,但JDK不提供这种构造方式

发生哈希冲突后怎么处理链表与红黑树

table[index]已有节点时,进入冲突处理流程:

立即学习Java免费学习笔记(深入)”;

MewXAI
MewXAI

一站式AI绘画平台,支持AI视频、AI头像、AI壁纸、AI艺术字、可控AI绘画等功能

下载
  • 先比哈希值,再用equals()比key(顺序不能反,哈希不等可直接跳过equals)
  • 如果找到相同key,新value覆盖旧value,返回旧值
  • 否则插入链表尾部(Java 8起用尾插法,避免多线程扩容时死链)
  • 链表长度≥8且table.length ≥ 64时,触发树化:TreeNode结构替换链表,转为红黑树
  • 红黑树中插入仍基于compareTo()hashCode()比较,不依赖equals()顺序

树化条件两个都必须满足,缺一不可;反向退化(树转链表)阈值是节点数≤6。

扩容时机与rehash的代价在哪

触发扩容的条件是:size > threshold(即元素数超过“容量 × 负载因子”,默认0.75)。扩容不是简单复制,而是整个table重建,所有已有key都要重新计算下标、重新插入。

关键细节:
- 新容量是原容量左移1位(×2),所以仍是2的幂
- rehash过程中,每个桶里的节点要么留在原下标,要么落到原下标 + 旧容量位置(因为新长度多一位bit)
- 这个规律被用于Java 8的高效迁移,不用全部重新hash & (newLength-1),但你写自定义map时别盲目套用——它依赖扰动哈希和2的幂设计

真正慢的是大量rehash叠加哈希冲突,而不是单次put。所以初始化时预估size、设好初始容量,比后期优化put逻辑更有效。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

241

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

641

2024.03.01

length函数用法
length函数用法

length函数用于返回指定字符串的字符数或字节数。可以用于计算字符串的长度,以便在查询和处理字符串数据时进行操作和判断。 需要注意的是length函数计算的是字符串的字符数,而不是字节数。对于多字节字符集,一个字符可能由多个字节组成。因此,length函数在计算字符串长度时会将多字节字符作为一个字符来计算。更多关于length函数的用法,大家可以阅读本专题下面的文章。

934

2023.09.19

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

613

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

283

2025.12.24

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

21

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

23

2026.01.21

C# 多线程与异步编程
C# 多线程与异步编程

本专题深入讲解 C# 中多线程与异步编程的核心概念与实战技巧,包括线程池管理、Task 类的使用、async/await 异步编程模式、并发控制与线程同步、死锁与竞态条件的解决方案。通过实际项目,帮助开发者掌握 如何在 C# 中构建高并发、低延迟的异步系统,提升应用性能和响应速度。

46

2026.02.06

Golang处理数据库错误教程合集
Golang处理数据库错误教程合集

本专题整合了Golang数据库错误处理方法、技巧、管理策略相关内容,阅读专题下面的文章了解更多详细内容。

67

2026.02.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3.4万人学习

C# 教程
C# 教程

共94课时 | 9万人学习

Java 教程
Java 教程

共578课时 | 61.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号