HashMap的扩容机制

HashMap的扩容在jdk1.7和jdk1.8有所不同,因为它在1.7和1.8的底层数据结构不同,在1.7的时候底层是由数组+链表来实现的,而在1.8的时候底层是由数组+链表+红黑树来实现的。

在jdk1.7的时候,当HashMap中元素的总个数超过阈值时会触发扩容,这个阈值是用数组容量*负载因子得到的,数组容量和负载因子的值默认分别是16和0.75,我们也可以在声明HashMap的时候去设置这两个值,比如可以将负载因子设置为一个小于0.75的值或者大于0.75的值都可以,只不过,如果我们将它的值设置为小于0.75,就会造成阈值很容易达到,而这时我们所声明的数组容量还有很大一部分没有使用到,就触发了扩容,造成了内存的浪费;而如果我们将负载因子设置为一个大于0.75的值,虽然可能降低了内存的浪费,但是会导致哈希碰撞发生的几率上升,而导致HashMap性能下降,所以不建议修改负载因子的值。而HashMap的初始化容量最好是在声明的时候给定,以避免HashMap的频繁扩容,因为HashMap的扩容是很消耗性能的一个操作。所以如果我们能根据业务需求预估这个值的话,还是要在声明HashMap的时候设置它的初始化容量。HashMap在扩容的时候是这么做的,当扩容条件达到的时候,会声明一个新的数组,新数组的容量是旧数组的两倍,因为HashMap是2倍扩容,然后将旧数组中的所有的元素重新进行hash运算以确定它们在新的数组中的位置,扩容的最大性能消耗就在这里。

在jdk1.8的时候,两种情况会触发扩容:一个是跟在jdk1.7中相同,HashMap中元素总个数超过阈值的时候触发;另一个是,当链表的长度达到了8而数组的长度还未超过64时,触发扩容。扩容时也是声明一个新的数组,长度为旧数组的两倍,只是在将元素从旧数组迁移到新数组时,无需重新对所有元素做hash运算,而是根据旧数组的长度做位运算就可以确定这些元素在新数组中的位置了,这使得扩容操作相较于在jdk1.7的时候性能有所提升,但我们仍然要避免HashMap频繁扩容的情况发生,最好还是要在声明HashMap的时候给定初始化长度。

还有一个不同就是:在jdk1.7中,每次扩容都会导致链表倒置,因为链表元素插入操作用的是头插的方式,而在jdk1.8中因为是位运算后的平移,所以不会导致链表倒置。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值