java学习之:HashMap源码分析

本文深入探讨HashMap的工作原理,包括其数据结构(数组+链表+红黑树)、put操作流程、扩容机制及内部hash算法。从JDK1.8前后的变化出发,详细解释HashMap如何处理哈希冲突和提升效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、HaspMap集合简介

基于哈希表的 Map接口的实现。这种实现提供了所有可选的Map操作,并允许 null值和 null关键。(这 HashMap类大致相当于 Hashtable,除了它是不同步的,允许空值。)此外hashMap中的映射不是有序的。
在jdk1.8以前,HashMap由数组和链表组成,数组是HaspMap的主体,而链表则是为了解决哈希冲突而引入的结构。而在jdk1.8以后,HashMap引入了红黑树的数据结构,当链表的长度大于默认值8,并且当前数组的长度大于64时,当前索引位置的所有数据改为红黑树存储,引入红黑树的目的其实也是为了提升HaspMap的效率。

这里我们总结一下Map特点:
1、存取是无序的。
2、键值对都可以存储null,但是键位置只能有一个null
3、键位置是唯一的。
4、数据结构:链表+数组+红黑树(1.8以后的版本)
5、边界值>8 && 数组长度>64,链表转红黑树。

二、HashMap的数据结构

HashMap的数据结构:
jdk 1.8之前:数组+链表
jdk 1.8之后:数组+链表+红黑树

2.1 put操作

我们先来看一下HashMap的整个存储过程结构图:
在这里插入图片描述
我们在创建HashMap集合对象的时候,在jdk1.8之前,会在构造函数中创建一个长度是16的Entry[] table 用来存储键值对数据,而在1.8以后,构造方法中不再创建数组,而是在第一次调用put方法时创建数组,Node[] table用来存储键值对数据。赋值过程是在resize()方法中。
如下图所示:
在这里插入图片描述在这里插入图片描述
HaspMap的hash算法采用的是无符号右移+按位异或的操作,我们思考一下,为什么会做这样的设计呢?其实也不难理解,设计者肯定是希望我们计算出来hash值尽量的分布均匀,而如下图所示:这种将高位与低位的异或算法正是可以达到hash值分布均匀的效果。
在这里插入图片描述
在hashMap中,当我们在进行put操作时时候如果计算出来的hashCode一样时,这个时候我们会判断它的equal值是否相等,相等则覆盖掉原来存储的对象,不相等则使用链表结构储存,当我们的链表长度大小超过8,并且数组的长度大于64的时候,这个时候就会将链表转成红黑树。如下图所示:
在这里插入图片描述

2.2 扩容机制

HashMap 的大小默认初始值是16,并且默认的加载因子是0.75,当我们的存储数据占用的空间超过当前容量大小*0.75的时候,这时候就会触发扩容,扩容的规则:每一次扩容,容量增加一倍。
在这里插入图片描述

2.3 继承关系

下图是我们HashMap的一个简单的继承关系图:克隆接口和序列化接口我们这里不做概述,HashMap的大部分功能都已经被它的父类AbstracMap实现了,接口Map则给我们提供了常用的操作接口。
在这里插入图片描述
HashMap提供了很多的构造器,但是基本上我们自己在使用的时候都是使用的默认构造器,有参构造器其实就是设置初始化容量和加载因子的值,当我们在使用HashMap之前知道我们所存储对象的数量时,选择有参构造可以避免不必要的扩容从而提升我们集合存储的效率。在设置初始容量时,也是有讲究的,我们初始容量必须满足2^n,即使用户设置不满足这个规则,HashMap在后台也会自动匹配一个与其最相近的2的n次幂。如下图所示,当用户设置不满足2的n次幂时,tableSizeFor()方法会匹配最相近的2的n次幂。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值