hashmap面试题总结

为什么要改成“数组+链表+红黑树”

主要是为了提升在 hash 冲突严重时(链表过长)的查找性能,使用链表的查找性能是 O(n),而使用红黑树是 O(logn)。

那在什么时候用链表?什么时候用红黑树?

对于插入,默认情况下是使用链表节点。当同一个索引位置的节点在新增后达到9个(阈值8):如果此时数组长度大于等于 64,则会触发链表节点转红黑树节点;
而如果数组长度小于64,则不会触发链表转红黑树,而是会进行扩容,因为此时的数据量还比较小。

对于移除,当同一个索引位置的节点在移除后达到== 6 个,并且该索引位置的节点为红黑树节点,会触发红黑树节点转链表节点==

为什么链表转红黑树的阈值是8?

阈值为8是在时间和空间上权衡的结果
红黑树节点大小约为链表节点的2倍,在节点太少时,红黑树的查找性能优势并不明显,付出2倍空间的代价

那为什么转回链表节点是用的6而不是复用8?

如果我们设置节点多于8个转红黑树,少于8个就马上转链表,当节点个数在8徘徊时,就会频繁进行红黑树和链表的转换,造成性能的损耗。

那 HashMap 有哪些重要属性?分别用于做什么的?

除了用来存储我们的节点 table 数组外,
1)size:HashMap 已经存储的节点个数;
2)threshold:扩容阈值,当 HashMap 的个数达到该值,触发扩容。
3)loadFactor:负载因子,扩容阈值 = 容量 * 负载因子。

threshold 除了用于存放扩容阈值还有其他作用吗?

我们新建 HashMap 对象时, threshold 还会被用来存初始化时的容量。
比如传入的参数是10,他会存储16
HashMap 直到我们第一次插入节点时,才会对 table 进行初始化,避免不必要的空间浪费。

HashMap 的默认初始容量是多少?HashMap 的容量有什么限制吗

默认初始容量是16。HashMap 的容量必须是2的N次方,HashMap 会根据我们传入的容量计算一个大于等于该容量的最小的2的N次方,例如传 9,容量为16。

HashMap 的容量必须是 2 的 N 次方,这是为什么

计算索引位置的公式为:(n - 1) & hash,当 n 为 2 的 N 次方时,n - 1 为低位全是 1 的值,此时任何值跟 n - 1 进行 & 运算的结果为该值的低 N 位,达到了和取模同样的效果,实现了均匀分布
只有n是2的N次方的时候,才满足和取模同样的效果
当 n 不为 2 的 N 次方时,hash 冲突的概率明显增大。

为什么是0.75而不是其他的?

这个也是在时间和空间上权衡的结果。如果值较高,例如1,此时会减少空间开销,但是 hash 冲突的概率会增大增加查找成本
而如果值较低,例如 0.5 ,此时 hash 冲突会降低,但是有一半的空间会被浪费,所以折衷考虑 0.75 似乎是一个合理的值。

HashMap 的插入流程是怎么样的?

这里截取我的笔记,否则排版有问题
在这里插入图片描述

计算 key 的 hash 值,是怎么设计的?

拿到 key 的 hashCode,并将 hashCode 的高16位和 hashCode 进行异或(XOR)运算,得到最终的 hash 值。
为了让高16为也参与到计算数组下标的过程中,减少hash冲突

扩容(resize)流程介绍下?

在这里插入图片描述

HashMap 是线程安全的吗?

不是。HashMap 在并发下存在数据覆盖
遍历的同时进行修改会抛出 ConcurrentModificationException 异常等问题,JDK 1.8 之前还存在死循环问题。

JDK 1.8 之前还存在死循环问题,介绍一下死循环问题?

导致死循环的根本原因是 JDK 1.7 扩容采用的是==“头插法”,会导致同一索引位置的节点在扩容后顺序反掉。而 JDK 1.8 之后采用的是“尾插法”==,扩容后节点顺序不会反掉,不存在死循环问题。

那总结下 JDK 1.8 主要进行了哪些优化?

底层数据结构从“数组+链表”改成“数组+链表+红黑树”,主要是优化了 hash 冲突较严重时,链表过长的查找性能:O(n) -> O(logn)。

计算 table 初始容量的方式发生了改变,老的方式是从1开始不断向左进行移位运算,直到找到大于等于入参容量的值;新的方式则是通过“5个移位+或等于运算”来计算。

优化了 hash 值的计算方式,老的通过一顿瞎操作,新的只是简单的让高16位参与了运算
新的只是简单的让高16位参与了运算

扩容时插入方式从“头插法”改成“尾插法”,避免了并发下的死循环。

Hashmap与Hashtable

Hashmap线程是不安全的,Hashtable是线程安全的
hashmap允许key=null
hashtable不允许 key=null
hashmap中 key=null的位置存放在数组的index=0的位置

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值