HashMap底层tableSizeFor(int i)方法变动

HashMap底层中tableSizeFor(int i)方法作用是确保底层数组扩容时新的数组容量为2的幂次数,即2n

jdk1.8:

static final int tableSizeFor(int cap) {
    int n = cap - 1;
    n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

(注意:n是从0开始计数)
我们知道2n表示为二进制时除去最高位第n位为1外,最高位后的位均为0,例如,8 => 1000。所以当一个数小于2n大于2n-1时,它的n-1位就是它的最高位,例如,6 => 110。
此外,我们知道2n-1其所有二进制位均为1,例如,7 => 8-1 => 0111。
因此我们的目标就是求得这个位数均为1的二进制数
tableSizeFor(int i)方法是通过向右移位并通过或运算来不断的替换最高位后的1,每次运算一次后1的个数就会翻倍,因此移位的数字依次为1,2,4,8,16。
0
jdk11:

static final int tableSizeFor(int cap) {
   int n = -1 >>> Integer.numberOfLeadingZeros(cap - 1);
   return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
public static int numberOfLeadingZeros(int i) {
    // HD, Count leading 0's
    if (i <= 0)
       return i == 0 ? 32 : 0;
    int n = 31;
    if (i >= 1 << 16) { n -= 16; i >>>= 16; }
    if (i >= 1 <<  8) { n -=  8; i >>>=  8; }
    if (i >= 1 <<  4) { n -=  4; i >>>=  4; }
    if (i >= 1 <<  2) { n -=  2; i >>>=  2; }
    return n - (i >>> 1);
}

首先观察tableSizeFor方法,我们发现返回语句并没有发生变化,这说明我们依旧是要求一个全为1的二进制串。
此外,-1在计算机中的二进制表示形式为1111 1111 1111 1111 1111 1111 1111 1111,全部为1。结合int n = -1 >>> Integer.numberOfLeadingZeros(cap - 1);语句得知我们需要cap - 1的二进制位数,然后用总位数减去二进制串的位数就是最后-1需要向右移动的位数。

注意:n是从0开始计数的。

接下来我们需要通过numberOfLeadingZeros方法来获取这个需要移动的位数。在该方法中通过位移来判断输入的数的位数。int n = 31是因为int类型的数是32位的,然后
与216比较判断是否超过16位,超过则进行移位减小并减小n的值
与28比较上一步余下的位数是否超过8位,超过则进行移位并减小n的值
与24比较上一步余下的位数是否超过4位,超过则进行移位并减小n的值
与22比较上一步余下的位数是否超过2位,超过则进行移位并减小n的值
最后n >>> 1确保余下的位数不超过1位,此时i的位数已经随着n的不断减小而减去,剩下的位数便是最后需要移位的位数,返回即可。

通过numberOfLeadingZeros方法得到移位位数后进行移位并加1得到最后的结果。
1
附录:

移位数移动后的二进制串+1
0111111111111111111111111111111110
11111111111111111111111111111111-2147483648
21111111111111111111111111111111073741824
311111111111111111111111111111536870912
41111111111111111111111111111268435456
5111111111111111111111111111134217728
61111111111111111111111111167108864
7111111111111111111111111133554432
811111111111111111111111116777216
9111111111111111111111118388608
1011111111111111111111114194304
111111111111111111111112097152
12111111111111111111111048576
131111111111111111111524288
14111111111111111111262144
1511111111111111111131072
16111111111111111165536
1711111111111111132768
181111111111111116384
1911111111111118192
201111111111114096
21111111111112048
2211111111111024
23111111111512
2411111111256
251111111128
2611111164
271111132
28111116
291118
30114
3112

END

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值