HashMap源码解析(上)

在面试中,HashMap的重要性,咱们不用多说了,那是相当重要的,咱们深入分析这个HashMap。

首先咱们先从以下几个方面来看HashMap:1.散列表实现 2.扰动函数 3.初始化容量 4.负载因子 5.扩容元素拆分

先来看看最简单的HashMap的散列表实现:

主要思想就是,使用生成的hashcode与数组长度做与运算,使得每个元素在这个数组中都有相应的位置。以下是小傅哥画的这个过程的示意图:

上述实现存在的问题:

可能因为Hash碰撞导致链表长度比较长,这样就不能发挥hash的威力

获取数组索引ID,需要的数组长度是2的倍数,这里面又有什么含义呢

时间效率和空间效率又该如何进行平衡呢

链表越来越长,该如何进行优化

元素的不断添加,会触发扩容的流程,原先的元素在新的数组上又该如何分配

带着以上疑问,我们逐一进行解答?

HashMap有一个函数如下:

这个函数在HashMap中叫扰动函数,可以看到HashMap不是直接获取hash值,而是进行了一次扰动计算,(h=key.hashcode()^(h>>>16))

把hash值右移16位,也就正好是自己长度的一半,之后与原hash值做异或运算,这样就混合了原hash值中的高位和低位,增大了随机性。

利用这个函数能有效的避免hash冲突,以此能解决第一个问题。

在HashMap初始化的方法中,有以上这一段方法,关键的部分是这个tableSizefor方法,这个方法能计算出扩容后的数组容量。

这里面涉及到大量的移位操作,而且移位操作的效率极高,所以采用2的幂次方作为扩容后的容量,是为了性能的保证。这里解释了第二个问题。

这里面还有个负载因子DEFAULT_LOAD_FACTOR=0.75f 的存在,负载因子主要决定HashMap要进行扩容逻辑的触发点,

0.75是专家经过大量的数学数据优化过后的最佳平衡值,当然你也可以用更多的空间来换时间上性能的提升,你可以把负载因子

调小一点,以减少碰撞。这里解释了第三个问题和第四个问题

扩容之后,数据的拆分和重新规划,原来1.7中需要重新计算hash值,但是1.8中做了优化,不再需要重新计算,提升了拆分的性能,设计的还是十分巧妙的。

1.8的实现如下:

原hash值与扩容新增出来的长度(这里指的不是最后的长度喔),进行&运算,如果值等于0,则下标位置不变,否则在原来位置基础上加上新增出来的长度,这样一来就不用重新计算每一个数组中的元素了。

1.8中对于不是第一次扩容的操作,其中容量会变为原来的两倍,阈值也会变为原来的两倍。

 

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值