HashMap中的天才想法--如何确保初始容量为2的n次幂

结论

HashMap能够确保它的初始容量为2的n次幂,除了指定大于2的30次方的值以外,无论你指定了什么值,最后都是2的n次幂

搬上大神的代码

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;
}

详细解释一下

对于下面这个数,我们假定它的值大于等于1,于是上述的算法是希望,能够向前进一位,并让后面的数都变成0,这样就可以实现“找到一个离给定容量最近的2的幂次方数作为数组的大小

HashMap中的天才想法--如何确保初始容量为2的n次幂_第1张图片

那要怎么达到这个目的呢?有一个很简单的方法,就是判断一下整型下允许的所有的2次幂,选一个比原值大的最小2次幂即可,比如

n = cap - 1;
if(n<2){
 n = 1;
}else if(n<4){
 n = 2;
}else if(n<8){
 n = 4;
}else if(n<16){
 n = 8;
}else if(n<32){
 n = 16;
}else if(n<64){
 n = 32;
}else if(n<128){
 n = 64;
}else if(...){
 ...
}

小一点的数效率还行,但是大了往后的效率就不好了。

或者我们也可以每次右移一位,判断当前值是否等于1,就能确定当前数的最高位的1是在哪个位置count,然后左移count+1即可

public static final int tableSizeFor2(int cap) {
    if (cap <= 1) {
      return 1;
    }
    int n = cap - 1;
    int count = 0;
    while (n != 1 && (n <= 3 || n >>> 1 != 1)) {
      count++;
      n = n >>> 1;
    }
    return count == 30 ? Integer.MAX_VALUE : n << (count + 1);
}

这个方式看起来也可以,效率上也不差,就是会多了几次的位移,比如129需要位移8次(最后一行可能还需要一次位移),源码中的唯一固定是4次。马马虎虎可以接受吧。

跑偏了,还是以图型表示一下源码中的计算结果吧

要想进一位,那么除了上述我自己想的方法以外还有一种方式,是将当前数中的所有0变成1,然后再加1就能进一位了,那怎么办呢

实际上我们不用管中间有几位,也不用管中间几位是或运算,与运算还是异或运算,我们只需要关注当前我们位移的那几位是或预运算就行。如下图

HashMap中的天才想法--如何确保初始容量为2的n次幂_第2张图片

是不是很简单? 

 

 

你可能感兴趣的:(java,java,hashmap)