HashMap的put和get的底层实现原理

HashMap的put和get的底层实现原理

在了解HashMap的底层实现原理的时候,我们首先了解HashMap的底层结构。

HashMap的底层是基于数组+链表实现的。但是jdk1.7和jdk1.8的实现有点不同。

HashMap的存储结构:
HashMap的底层是基于数组+链表实现的。但是jdk1.7和jdk1.8的实现有点不同。

HashMap的存储结构:
1.hashmap底层是以数组方式进行存储。将key-value对作为数组中的一个元素进行存储。
2.key-value都是Map.Entry中的属性。其中将key的值进行hash之后进行存储,即每一个key都是计算hash值,然后再存储。每一个Hash值对应一个数组下标,数组下标是根据hash值和数组长度计算得来。
3.由于不能保证两个不同的key有相同的hash值,即该位置的数组中的元素出现两个,对于这种情况,hashmap采用链表形式进行存储。

Jdk1.7:
底层实现
基本构造:
1.初始化桶大小,因为底层是数组,所以这是数组默认的大小。
2.桶最大值。
3.默认的负载因子(0.75)
4.table 真正存放数据的数组。
5.Map 存放数量的大小。
6.桶大小,可在初始化时显式指定。
7.负载因子,可在初始化时显式指定。

HashMap的默认容量为16,负载因子是0.75,当我们在使用HashMap的时候,不断给HashMap中存放值,当数量达到了12(16*0.75)的时候,就需要进行扩容,扩容涉及到了rehash复制数据等操作,所以扩容会消耗资源。因此我们在使用的时候,可以提前预估HashMap的容量最好。

Put的底层实现原理:
在这里插入图片描述
首先我们去判断当前数组是否需要初始化,如果不需要初始化,就判断key值是否为空,如果为空,那就直接put一个空值进去,然后根据key去计算hashcode值,这样的话我们就可以知道索引的下标(元素存放位置),如果那个位置是 一个链表则需要遍历判断里面的 hashcode、key 是否和传入 key 相等,如果相等则进行覆盖,并返回原来的值如果当前位置没有元素,那就直接添加一个Entry对象到当前位置(调用addEntity写入Entity时需要判断是否需要扩容)。
Get的底层实现原理:

首先也是根据 key 计算出 hashcode,然后定位到具体的桶中。
判断该位置是否为链表。
不是链表就根据 key 的 hashcode 是否相等来返回值。
为链表则需要遍历直到 key 及 hashcode 相等时候就返回值。
啥都没取到就直接返回 null
Jdk1.7的缺点:当hash冲突严重时,形成的链表会越来越长,这样的话,查询的效率会越来越低。
因此在jdk1.8中进行了优化。

Jdk1.8:
Put的底层实现原理:
1.判断当前桶是否为空,空的就需要初始化(resize 中会判断是否进行初始化)。
2、根据当前 key 的 hashcode 定位到具体的桶中并判断是否为空,为空表明没有 Hash 冲突就直接在当前位置创建一个新桶即可。
3、如果当前桶有值( Hash 冲突),那么就要比较当前桶中的 key、key 的 hashcode 与写入的 key 是否相等,相等就赋值给 e,在第 8 步的时候会统一进行赋值及返回。
4、如果当前桶为红黑树,那就要按照红黑树的方式写入数据。
5、如果是个链表,就需要将当前的 key、value 封装成一个新节点写入到当前桶的后面(形成链表)。6、接着判断当前链表的大小是否大于预设的阈值,大于时就要转换为红黑树。
7、如果在遍历过程中找到 key 相同时直接退出遍历。
8、如果 e != null 就相当于存在相同的 key,那就需要将值覆盖。
9、最后判断是否需要进行扩容。

Get方法的底层实现原理:
1、首先将 key hash 之后取得所定位的桶。
2、如果桶为空则直接返回 null 。
3、否则判断桶的第一个位置(有可能是链表、红黑树)的 key 是否为查询的 key,是就直接返回 value。
4、如果第一个不匹配,则判断它的下一个是红黑树还是链表。
5、红黑树就按照树的查找方式返回值。
6、不然就按照链表的方式遍历匹配返回值。
HashMap的遍历方式:entrySet(推荐使用,因此使用entrySet遍历后,可以取出key和value)、keyset(需要通过key来取出value)等等方法

当我们给hashmap中存储值(put)的时候,hashMap的底层首先去通过key进行hash计算,通过计算出的hashcode值和数组的长度进行取模,从而算出该值应该存放的地址/下标(index)
由于在计算中位运算比取模运算效率高的多,所以HashMap规定数组的长度为 2^n。这用
2^n - 1做位运算与取模效果一致,并且效率还要高出许多。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
HashMap是一种常用的Java集合类,它是基于哈希表实现的。在HashMap中,键和值都是以键值对的形式存储的。当我们调用put(key, value)方法将键值对存储到HashMap中时,首先会对键调用hashCode()方法来计算哈希值。哈希值用于确定该键值对在哈希表中的存储位置,这个位置被称为bucket。每个bucket中都会存储一个或多个键值对,这些键值对以Map.Entry的形式存在。 在HashMap内部,它通过对键的哈希值进行与运算(hash & (length-1))来确定键值对的存储位置。这样可以使得键值对均匀地分布在哈希表的各个bucket中,提高了HashMap的查找效率。当我们调用get(key)方法从HashMap中获取值时,HashMap会先根据键的哈希值找到对应的bucket,然后再遍历该bucket中的键值对,找到匹配的键值对并返回对应的值。 了解HashMap底层实现原理对于理解HashMap的工作机制非常重要。HashMap通过哈希表的方式存储键值对,通过键的哈希值来确定存储位置,从而实现了高效的存取操作。同时,理解HashMap的put()和get()方法的工作原理也是面试中常见的问题。 <span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [HashMap实现原理分析](https://blog.csdn.net/qq_25827845/article/details/89075398)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [HashMap底层实现原理及面试问题](https://blog.csdn.net/guorui_java/article/details/113827854)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值