HashMap从Threshold到Integer numberOfLeadingZeros

为了易于理解HashMap的resize方法,我觉得还是先得弄懂Threshold是怎么来的。
首先看Threshold的JavaDoc

 /**
     * The next size value at which to resize (capacity * load factor).
     *
     * @serial
     */

在下一次resize时候的数组长度大小的值(capacity * load factor)容量x负载系数
这里依我所见load factor应该就是指的loadFactor,因为loadFactor的JavaDoc,同时根据DEFAULT_LOAD_FACTOR的JavaDoc在未指定负载系数的构造函数时使用0.75F作为负载系数

 /**
     * The load factor for the hash table.
     *
     * @serial
     */
    final float loadFactor;
	/**
     * The load factor used when none specified in constructor.
     */
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

在构造函数当中,初始Threshold的方法tableSizeFor(),返回一个2的幂次的数字作为给定的目标容量cap在构造函数为初始化塞入的initialCapacity

	/**
     * Returns a power of two size for the given target capacity.
     */
    static final int tableSizeFor(int cap) {
    	//获取到cap-1的非0最高位之前0的个数然后将-1无符号右移
        int n = -1 >>> Integer.numberOfLeadingZeros(cap - 1);
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

在看到这个方法的时候,不禁黑人问号Integer.numberOfLeadingZeros(cap - 1);是什么东西?
然后再点进去,更是一脸蒙蔽,这个是啥玩意,然后百度了下发现是返回无符号整形的最高位非0位之前0的个数

@HotSpotIntrinsicCandidate
    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);
    }

来逐层分析
if (i <= 0)
return i == 0 ? 32 : 0;
当i==0的时候返回32,当i<0的时候返回0

为了便于理解首先写32个0
00000000000000000000000000000000
1<<16 1左移16位 即
00000000000000000000000000000001 == 1 == 2^0
末尾的1左移16位
00000000000000010000000000000000 == 65536 == 2^16
int n = 31 ,因为当i>0的时候,i取值范围最极端的情况是当i=1的时候非0的最高位前面有31个0因此取值31
if (i >= 1 << 16) { n -= 16; i >>>= 16; }
如果i>=1<<16即i>=2^16 i>= 65536
n = n-16 = 15 i>>>=16 i无符号右移16位,因为i已经大于等于了65536因此最极端的情况下即i=65536非0最高位前面也只有15个0

if (i >= 1 << 8) { n -= 8; i >>>= 8; }
如果i>=1<<8即i>=2^8 i>= 256
n = n-8 = 23 i>>>=8 i无符号右移8位,因为i已经大于等于了256因此最极端的情况下即i=256非0最高位前面也只有23个0下面同理

需要注意的是if判断的时候并不是if else的判断,因此存在如果当i=65536的时候,在第一次判断的时候会将i>>>16位,直接将i=1了,因此直接return n-(i>>>1)
这段代码就是通过不断的折半然后寻找到i的非0最高位之前0的个数
-1的二进制为
1111111111111111111111111111111111得到的方法
1的二进制000000000000000000000000000000001
取反
1111111111111111111111111111111110
加一得补码1
1111111111111111111111111111111111
因此可以知道int的正数范围为
000000000000000000000000000000001到0111111111111111111111111111111111
负数的范围
1111111111111111111111111111111111到100000000000000000000000000000000
而在tableSizeFor方法中-1无符号右移cap-1的非0最高位前0的个数的目的就是为了得到比cap大的最小的2的幂次方数-1的数,
-1>>>Integer.numberOfLeadingZeros(cap - 1)
最后如果n<0,直接return 1 如果超过了2^30 次方就返回 230(因为-1如果无符号右移大于230就说明为int的最大值,如果再+1就越界了),没有就返回n+1,

Integer.numberOfLeadingZeros(cap - 1),为什么是cap-1,当cap为2的时候,因为我们只需要得到比cap大的2的幂次方数,可以包括本身,如果是cap是一个2的幂次方数我们不减一进行计算将获得(31-幂次)的值而-1无符号右移的时候会获取一个2^(n+1)-1的值,最后进行+1会是cap的两倍,而我们只需要获取到本身这个2的幂次方值

ps:吐个槽,最近加班太累了,源码的阅读真的是一层套一层,简直老千层饼了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值