详细解释HashMap中tableSizeFor函数

最近在看一些集合的源码,看到HashMap感觉用到了很多移位运算的技巧,看了好一会儿才明白,记一下以免以后再忘了

后面有时间会整理完整的源码

HashMap中有这样一段代码,当初始化HashMap时,如果指定了初始容量initialCapacity,由于哈希桶的数目必须是2的n次幂,因此要把initialCapacity转化为比它大的最小的2的n次幂数,例如initialCapacity = 10 ,那就返回16, initialCapacity = 17,那么就返回32。

 /**
     * Returns a power of two size for the given target capacity.
     */
    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;
    }

以上代码就是转换的代码,首先考虑一下如果我要实现这样一个转换的思路:首先通过一个循环去判断int值的二进制表示中,最高位的1是第几位,然后返回一个最高位+1的的2的幂数,这样需要循环31次,代码如下:

public static int convert(int initialCapacity) {
		int a = 1 ;
		int ans = 1;
		int c = initialCapacity - 1 ;  //减1的目的是避免当initialCapacity = 2^n时,返回结果2^n+1
		for(int i=1;i<31;i++) {
			a = a << 1;
			if((c & a) > 0)
				ans = i;
		}
		return 1 << (ans + 1);
	}

jdk源码的做法是通过5次无符号移位运算以及或运算就得到了这个值,分析一下做法:

n第一次右移一位时,相当于将最高位的1右移一位,再和原来的n取或,就将最高位和次高位都变成1,也就是两个1;

第二次右移两位时,将最高的两个1向右移了两位,取或后得到四个1;

依次类推,右移16位再取或就能得到32个1;

最后通过加一进位得到2^n 。

 

注意,当initialCapacity本身就是2^n时,结果会是2^n+1,为了避免出现这样的情况,在一开始将initialCapacity-1,只要该数不是2^n(10000....),减1不会影响最高位1的位置。

举例说明:

例1

10的二进制是1010,减1就是1001

第一次右移取或: 1001 | 0100 = 1101 ;

第二次右移取或: 1101 | 0011 = 1111 ;

第三次右移取或: 1111 | 0000 = 1111 ;

第四次第五次同理

最后得到 n = 1111  ,返回值是 n+1 = 2 ^ 4 = 16 ;  

例2

16的二进制是10000,减1变为01111,移位取或运算之后,返回的就是16

如果不减1,输入10000,移位取或运算之后得到的是11111,返回的是32

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值