JDK中的HashMap

本文介绍了JDK中HashMap的数据存储方式,强调了其键值对的映射关系和键的唯一性。详细阐述了HashMap的底层实现,包括JDK8前后的数组+链表/红黑树结构,以及负载因子、树化阈值等关键属性。哈希函数的计算过程也被详细解析,包括如何处理哈希冲突和提高查找效率。同时,强调了重写hashCode()和equals()方法的重要性,以确保Key的唯一性和正确性。

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

哈希表保存数据:

HashMap保存数据时是使用<K,V>(键值对)保存的,键值对是一种映射关系,一个Key对应一个Value值。K值具有唯一性,当我们保存相同的K值时,Value值会被新的Value所覆盖,不会存在有两个相同的K值。

JDK中哈希表的底层原理:

HashMap查找的效率极高,时间复杂度O(1),这是一个非常高的查找效率,哈希表也是典型的用空间来换时间的一个数据结构。首先我们要明白哈希表底层是怎么实现的。在JDK8中,哈希表的底层是数组+链表/红黑树。当达到一定条件的时候链表会转换成红黑树,这个我们等等再进行介绍。而在JDK8之前的哈希表都是使用数组+链表的结构,没有引入红黑树这个数据结构。既然哈希表的底层是数组的一种形式,那我们知道数组在知道索引的情况下,查找的效率就是O(1),所以我们隐隐约约可以感觉到,哈希表查找的效率这么高,和索引离不开关系。哈希表通过哈希函数对Key进行哈希得到一个哈希值,这个哈希值对应的就是数组的索引,然后把这数据放入数组索引对应的位置,然后我们查找的时候也就是使用这个哈希值进行搜索,所以查找的时间复杂度可以达到O(1)。

JDK哈希表底层的一些属性:

 DEFAULT_LOAD-FACTOR:通过注释我们可以知道,这个数据代表了一开始的数组长度为16,而且扩容必须是2倍扩容。

MAXIMUN_CAPACITY:最大容量为2^30这么大。

DEFAULT_LOAD_FACTOR: 负载因子大小(存储元素/数组长度)

TREEIFY_THRESHOLD:这个代表了当我们的链表长度为8的时候就会树化,但是树化还有一个条件。

UNTREEIFY_THRESHOLD:当链表长度为6的时候,就会取消树化操作。

MIN_TREEIFY-CAPACITY:这也是我们树化的第二个条件,那就是数组长度>=64和链表长度>=8时才会进行树化操作。

哈希函数:

通过查看JDK的哈希表的源码我们可以看到JDK的哈希值是先使用JDK中的hashCode函数把Key转换成一个哈希值,然后将这个哈希值右移16位与一开始的哈希进行异或,这样会使得的出来hash值比较均匀分布,最后我们通过(n-1)&hash值得到最后索引的位置,其实(n-1)&hash这个操作本质上就是取模操作,只是位运算的速度更快,所以没有直接进行取模。这样我们通过整个hash函数就可以得到要存放元素位置的索引,从而进行高效查找。

关于哈希表存储数据:

那我们的链表又是来做啥的呢,接下来我们就来介绍链表的作用,当我们不同Key值经过哈希函数的计算可能会得到一样的hash值,我们把这样的事情叫做哈希冲突。哈希冲突在理论上一定是会发生的。我们一般有两种办法来解决哈希冲突:开散列和闭散列两种方式。我们JDK是使用开散列来解决这个问题,开散列也就是我们俗称的哈希桶,在JDK8中我们通过尾插法将hash值相同的元素连接在链表的尾部,这样如果我们进行搜索我们不需要遍历整个数组,而只需要遍历链表来寻找,大大增加了查找的效率,当链表过长的时候就会将链表树化成一棵红黑树来增加查找效率。当我们存储完之后,发现超过了负载因子,那这时候数组就会进行扩容,而扩容之后原本的数组对应的索引存放的元素会进行重新hash,放在新的索引位置。这里我只截取一部分源码。

hashCode()和equals()方法:

为什么我们重写hashCode()方法的时候也需要重写equals()方法呢。我们需要明确,当我们的hashCode相同的时候,不代表equals会相同,我们举一个例子,比如我们有两个数据:美丽和美景。我们假设hashCode都是美这个字,这时候我们发现equals之后会显示false,所以hashCode相同equals不一定相同,而equals相同,hashCode一定相同。那有什么作用呢,当我们存储数据时,发现hash值相同,但是我们需要保证Key的唯一性,所以我们需要借助equals方法来帮助我们比较这个Key是否在该链表中存在,如果存在则覆盖旧的Value值,不存在,则进行尾插法。这时候equals()方法的价值就体现出来了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值