面试问题简述

1. 简述一下Java HashMap的实现原理

HashMap底层维护了一个Node类型的数组table, 默认是Nulltable数组中的元素是一个链表,并在某些条件下会将链表转化为红黑树。

​ 当创建HashMap对象时,会将加载因子(loadFactor)初始化为0.75

​ 当我们向table数组中添加一个K-V键值对时,会根据当前的Key得到一个hash值,然后在底层将这个hash值转化为一个索引值(index = hash & (cap - 1)),这个索引值决定了该元素在table数组中应该存放的位置。

​ 当table数组索引处对应的位置没有元素存在时,直接将该键值对加入到table数组中。反之,则进行判断,如果当前要添加的键值对的key与该位置的键值对key相等,则放弃添加该元素,并用新的value替换掉旧的value,同时返回旧值。如果当前元素的key与已存在元素的key不相等,则判断table数组改索引处的后面元素是一个链表还是一颗红黑树

​ 若判断table数组该索引的位置是一个链表,则继续判断该链表中的元素有无与当前元素相同的key,若有,则用新值替换旧值,同时返回旧值。若无,则直接将当前的键值对挂在到链表的后面。若判断该索引处的元素是一颗红黑树,则用红黑树的方式去添加元素。

​ 第一次向HashMap中添加元素时,HashMap会先进行一次扩容,默认容量是16,同时计算出一个临界阈值:容量 * 0.75 = 12;之后,当table数组中的元素超过临界值时,就要对table数组进行扩容,新容量是就旧容量的2倍,同时计算出一个新的临界阈值,以此类。

​ 在JDK17中,如果table数组中的某一条链表的元素个数达到或者超过了TREEIFY_THRESHOLD (默认是8),并且table数组的长度达到或者超过了MIN_TREEIFY_CAPACITY(默认是64),则底层会将该链表进行树化,将其转换为一颗红黑树,否则仍然采用数组扩容机制。

2.能详细说一下HashMap的扩容过程吗

​ 当HashMap计算出一个新的容量值后,内部会重新创建一个新的Node数组table,接着会遍历旧的table,然后做如下判断:

  • 如果索引下只有一个元素,则使用该元素的hash值结合新的table容量计算出一个新的索引,并将该元素放入新table索引位置,同时将旧table索引下的元素置空。
  • 如果这个索引处是一个链表,则要对链表中的所有元素的hash值进行重新的插入。具体做法是:基于元素的hash值,将他们拆分成两部分,低位部分继续保存在原索引(oldIndex)位置,高位部分则放入[oldIndex + oldCap]。这种做法的数学原理,当容量扩大二倍后, 如果一个元素的hash & oldCap == 0 ,那么该Hash值使用newCap计算出的新index与旧index相同,而hash & oldCap == 1的元素,使用newCap计算出的newIndex = (oldIndex + oldCap)
  • 如果该索引处是一个树,则遍历该树上的全部元素,并根据hash拆分成两部分,低位部分和高位部分,低位部分放入旧索引位置,高位部分放入[oldIndex + oldCap]索引位置。如果两部分的节点个数小于UNTREEIFY_THRESHOLD(通常为6),则将其转换成一个链表结构,否则将其转换为树结构。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值