HashMap tableSizeFor

前言

先说点废话,虽然开发多年,但是从来没有看过源码,但是这次看HashMap源码个人真的感觉比较困难,还是那句话,鄙人不才,只是简单记载个人心得,如有不对欢迎指正。

首先简单介绍>>>:为无符号右移 ,高位补0.

可参考:

java中的移位运算符:<<,>>,>>>总结 - Hongten - 博客园

JDK版本17

/**
 * Returns a power of two size for the given target capacity.
     返回给定目标容量的2次幂大小
 */
static final int tableSizeFor(int cap) {
    int n = -1 >>> Integer.numberOfLeadingZeros(cap - 1);
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

其实上述代码可以进行拆解理解:

首先先讲numberOfLeadingZeros方法:

通俗来讲:就是从左边第一个位开始累加0的个数,直到遇到一个非零

Returns the number of zero bits preceding the highest-order ("leftmost") one-bit in the two's complement binary representation of the specified int value. Returns 32 if the specified value has no one-bits in its two's complement representation, in other words if it is equal to zero.
Note that this method is closely related to the logarithm base 2. For all positive int values x:
floor(log2(x)) = 31 - numberOfLeadingZeros(x)
ceil(log2(x)) = 32 - numberOfLeadingZeros(x - 1)
Params:
i – the value whose number of leading zeros is to be computed
Returns:
the number of zero bits preceding the highest-order ("leftmost") one-bit in the two's complement binary representation of the specified int value, or 32 if the value is equal to zero.
Since:
1.5
@IntrinsicCandidate
// 首先在jvm中一个int类型的数据占4个字节,共32位,其实就相当于一个长度为32的数组。
	// 那我们要计算首部0的个数,就是从左边第一个位开始累加0的个数,直到遇到一个非零值。
	public static int numberOfLeadingZeros(int i) {
		if (i == 0)                                                                       
            	return 32;
		int n = 31;
		// 下面的代码就是定位从左边开始第一个非零值的位置,在定位过程中顺便累加从左边开始0的个数
		// 将i无符号右移16位后,有二种情况;
		//   情况1.i=0,则第一个非零值位于低16位,i至少有16个0,同时将i左移16位(把低16位移到原高16位的位置,这样情况1和情况2就能统一后续的判断方式)
		//   情况2.i!=0,则第一个非零值位于高16位,后续在高16位中继续判断
		// 这个思路就是二分查找,首先把32位的数分为高低16位,如果非零值位于高16位,后续再将高16位继续二分为高低8位,一直二分到集合中只有1个元素
		if (i >>> 16 == 0) { n += 16; i <<= 16; }//65536
		// 判断第一个非零值是否位于高8位
		if (i >>> 24 == 0) { n +=  8; i <<=  8; }  //256
		// 判断第一个非零值是否位于高4位
		if (i >>> 28 == 0) { n +=  4; i <<=  4; }//16
		// 判断第一个非零值是否位于高2位
		if (i >>> 30 == 0) { n +=  2; i <<=  2; } //4   
		// 判断第一个非零值是否位于左边第一位
		n -= i >>> 31;                                                                
		return n;
	}
    以257为例返回结果为23,二进制码为1 0000 0001 向右移8 结果为1
    第一次在i >= 1 <<  8处计算 31-8 =23   
   以255为例返回结果为24,二进制码为1111 1111 向右移4位 i结果为1111,n=31-4=27,  向右移2 1111向右移2位,i结果为11,n=27-2=25
    最后 n-(11>>>1)) 实为return 25-1=24 
    但是值得注意的是 这里入参的i实际 i=cap-1,也就是 257实际对应258如此类推
}

-1移位问题:

-1的二进制码是1111 1111 1111 1111 1111 1111 1111 1111 三十二位

int n = -1 >>> Integer.numberOfLeadingZeros(cap - 1);

这样看来,其实也就是Integer.numberOfLeadingZeros获取了这个数据多少个零 ,就直接可获得这个数据所处二进制位数的最大值,

例如当cap为 258时,1 0000 0010 ,则补全为0000 0000 0000 0000 0000 0001 0000 0010

返回给定目标容量的2次幂大小

 return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;

在此还希望大家了解下为什么HashMap的数组长度总是2的次幂:

hashmap为什么长度要是2的n次幂_darkness0604的博客-CSDN博客_为什么hashmap的长度是2的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值