HashMap 容量为什么总是为 2 的次幂?

Posted Java技术栈

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HashMap 容量为什么总是为 2 的次幂?相关的知识,希望对你有一定的参考价值。

Java技术栈

www.javastack.cn


HashMap是根据key的hash值决策key放入到哪个桶(bucket)中,通过 tab=[(n - 1) & hash] 公式计算得出,其中tab是一个哈希表。
1. 为什么要保证 capacity 是2的次幂呢?

2)因为 n 永远是2的次幂,所以 n-1 通过 二进制表示,永远都是尾端以连续1的形式表示(00001111,00000011)
当(n - 1) 和 hash 做与运算时,会保留hash中 后 x 位的 1
例如 00001111 & 10000011 = 00000011


这样做有2个好处


  • &运算速度快,至少比%取模运算块
  • 能保证 索引值 肯定在 capacity 中,不会超出数组长度
  • (n - 1) & hash,当n为2次幂时,会满足一个公式:(n - 1) & hash = hash % n
2.为什么要通过 (n - 1) & hash 决定桶的索引呢?
3)首先要提的一点是 中 capacity 可以在构造函数中指定,如果不指定默认是2 的 (n = 4) 次方,即16。
public HashMap(int initialCapacity) {
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
}


4) 中的hash也做了比较特别的处理,(h = key.hashCode()) ^ (h >>> 16)。
先获得key的 的值 h,然后 h 和 h右移16位 做异或运算。
实质上是把一个数的低16位与他的高16位做异或运算,因为在前面 (n - 1) & hash 的计算中,hash变量只有末x位会参与到运算。使高16位也参与到hash的运算能减少冲突。

例如1000000的二进制是 

00000000 00001111 01000010 01000000 

右移16位:                     

00000000 00000000 00000000 00001111

异或                                

00000000 00001111 01000010 01001111


static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}


3.capacity 永远都是 2 次幂,那么如果我们指定 initialCapacity 不为 2次幂时呢,是不是就破坏了这个规则?
答案是:不会的, 的tableSizeFor方法做了处理,能保证n永远都是2次幂。
/**
 * Returns a power of two size for the given target capacity.
 */

static final int tableSizeFor(int cap) {
    //cap-1后,n的二进制最右一位肯定和cap的最右一位不同,即一个为0,一个为1,例如cap=17(00010001),n=cap-1=16(00010000)
    int n = cap - 1;
    //n = (00010000 | 00001000) = 00011000
    n |= n >>> 1;
    //n = (00011000 | 00000110) = 00011110
    n |= n >>> 2;
    //n = (00011110 | 00000001) = 00011111
    n |= n >>> 4;
    //n = (00011111 | 00000000) = 00011111
    n |= n >>> 8;
    //n = (00011111 | 00000000) = 00011111
    n |= n >>> 16;
    //n = 00011111 = 31
    //n = 31 + 1 = 32, 即最终的cap = 32 = 2 的 (n=5)次方
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}


 
   
   
 

https;?/blog.csdn.net/u010841296/article/details/82832166

- END -

推荐阅读:
1、
2、
3、
4、
5、
关注 Java技术栈 公众号在后台回复: Java ,可获取一份栈长整理的最新 Java 技术干货。

点击「阅读原文」带你飞~ 

以上是关于HashMap 容量为什么总是为 2 的次幂?的主要内容,如果未能解决你的问题,请参考以下文章

为什么HashMap建议初始化容量,且容量为2的次幂?

linux kfifo 为啥 保证缓冲空间的大小为2的次幂

HashMap源码之构造函数--JDK1.8

jdk1.8 HashMap底层数据结构:深入解析为什么jdk1.8 HashMap的容量一定要是2的n次幂

HashMap 源码理解与面试

南桥-- 算法训练 2的次幂表示