HashMap-九大问题

一,九大问题

1.1 问题一

存储在Node中的hash值, 是否就是key的hashCode()?

static final int hash(Object key) {
  int h;
  //hashCode和右移16进行按位异或运算
  return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

答案:不是。存储的是对Key先做hashCode()计算, 然后再无符号右位移16, 再按位异或

1.2 问题二

如何知道一个节点到底存储在Hash表(散列表)的哪个位置?

答案:根据key计算相关的hash值(并不是简单的hashCode()), (数组长度-1) & hash进行计算得出具体的下标, 如果下标只有这一个节点, 直接返回, 非一个节点, 继续在链表或者红黑树中查找

1.3 问题三

什么时候需要把链表转为红黑树?

答案:链表的节点数大于8(从0开始的, 多以判断条件为 >=7), 数组的长度必须大于等于64,这个时候就会转成红黑树 要么就会数组的扩容。

1.4 问题四

什么时候扩容?

答案:

情况一:

HashMap的Size达到Hash中数组长度*loadFactor(扩容因子)时扩容。即比threshold大, 进行扩容。每次扩容为原数组长度的一倍(<< 1)

情况二:

Hash表中某个链表长度到达8,且Hash表中数组的长度小于64.

1.5 问题五

Hash表中数组最大长度为多少?

答案:最大长度为 1<<30. 即:2的30次方法。

计算操作时,发现Hash表中数组长度为2的倍数效率最高,需要一直保持长度为2的倍数。数组长度最大取值为2的31次方减一。所以里面最大的2的倍数为2的30次方。

1.6 问题六
  1. Hash表中使用的是单向链表还是双向链表?

答案:单项链表

2. 数组扩容时, 链表使用的是尾加还是头加?

答案:JDK1.8尾插法 JDK1.7及以前采用的是头插法

1.7 问题七

链表转为红黑树时,数组中是所有的链表都转为红黑树,还是什么情况?

答案:只有数组里某个下标中的节点个数>8, 并且数组长度>=64, 该下标中的链表转换为红黑树

1.8 问题八

为什么java8中长度超过8以后将链表变为红黑树?

答案:红黑树的查询效率高于链表

1.9 问题九

为什么选择8作为转换值?

答案:元素个数为8的红黑树中,高度为:4.最多查找4次就能找到需要的的值,长度为8的链表,最多找7次。

例如长度为4就转换。红黑树高度为3,最多找3次。链表最多3次。

例如长度为7就转换。红黑树高度3,最多找3次。链表最多6次。多找3次和转换的性能消耗比较不值得。

在源码上可以看出,在理想状态下,受随机分布的 hashCode 影响,链表中的节点遵循泊松分布,而且根据统计,链表中节点数是 8 的概率已经接近千分之一,而且此时链表的性能已经很差了,所以在这种比较罕见和极端的情况下,才会把链表转变为红黑树

二. 总结HashMap底层原理(特别常见面试问题)

从Java8开始HashMap底层由数组+链表+红黑树。

使用HashMap时,当使用无参构造方法实例化时,设置扩容因子为默认扩容因子0.75。

当向HashMap添加内容时,会对Key做Hash计算,把得到的Hash值和数组长度-1按位与,计算出存储的位置。

如果数组中该没有内容, 直接存入数组中(Node节点对象), 该下标中有Node对象了, 把内容添加到对应的链表或红黑树中。

如果添加后链表长度大于等于8,会判断数组的长度是否大于等于64,如果小于64对数组扩容,扩容长度为原长度的2倍,扩容后把原Hash表内容重新放入到新的Hash表中。如果Hash长度大于等于64会把链表转换红黑树。

最终判断HashMap中元素个数是否已经达到扩容值(threshold),如果达到扩容值,需要进行扩容,扩容一倍。

反之,如果删除元素后,红黑树的元素个数小于等于6,由红黑树转换为链表。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值