hashmap 不释放空间_刁难问题,为什么HashMap默认容量为16加载因子为0.75

前言:实际开发中我们大多数都是只能new HashMap<>来存储键值对,很少会去设置初始容量,虽然我们知道他的默认容量是16。但是在面试中,为了体现你个人好学的能力,还是会被经常问到为什么默认容量是16,hashMap的底层了解吗这类问题。说下小编最近碰见的面试题。

面试官:HashMap的容量为什么是16?

我:设置16是因为是2的幂,符合内部计算的机制,而且这个值,不大也不小,太小了就有可能频繁发生扩容,影响效率。太大了又浪费空间。而加载因子0.75的是为了提高空间利用率和减少查询成本的折中,0.75的话碰撞最小。

这里解释下为什么这么说。看过HashMap源码的都应该知道存储数据要经过hash(key)和indexFor(h,length)来确定存储在哪个位置

796b83161cf250c1cb193f75f51cc0bf.png

hashMap源码

那么return h & (length-1) 是什么意思呢?其实,他就是取模。Java之所有使用位运算(&)来代替取模运算(%),最主要的考虑就是效率。因为位运算直接对内存数据进行操作,不需要转成十进制,所以位运算要比取模运算的效率更高。

换算过来就是这样的公式:X % 2^n = X & (2^n – 1)

可能大家还是看不懂,我写一个例子:

cd0756bfd946e494f0444fb6b25969ff.png

取模例子

所以这里出现一个重要点就是只要保证length的长度是2^n 的话,就可以实现取模运算。也就是我上面提到的容量必须满足2的幂。这里就会有人提出不是可以自定义扩容吗,那我就不设置成2的幂,怎么招呢,其实人家也不傻,早都想好怎么对付你了。从源码中可以看得出,他不一定会采用你设置的,你设置的不合理,他会自己计算出一个合理的值。比如我设置为5

04170292677779df785b0e69bd69f7b4.png

取出容量大小

可以看得出容量变为8,如果设置成9,就会变成16。这里有一个规律,就是可以把不合理的数转化成第一个比他自身大的2的幂的数,比如5只有2^3=8,才是第一个比5大的,所以就设置为8。

在HashMap中,threshold = loadFactor * capacity。

loadFactor是加载因子,表示HashMap满的程度,默认值为0.75f。对于一个默认的HashMap来说,当其size大于12(16*0.75)时就会触发扩容。为什么说0.75是折中选择呢?加载因子过高,例如为1,虽然减少了空间开销,提高了空间利用率,但同时也增加了查询时间成本;加载因子过低,例如0.5,虽然可以减少查询时间成本,但是空间利用率很低,同时提高了rehash操作的次数。所以,一般在使用HashMap时建议根据预估值设置初始容量,减少扩容操作。选择0.75作为默认的加载因子,完全是时间和空间成本上寻求的一种折中选择。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值