hashMap的容量(capacity)为什么必须是是2的n次方

HashMap的容量(桶的数量)为什么要是2的n次方

查看hashmap的源码可以发现,如果new一个hashmap对象不指定容量(capacity)的话,hashmap的默认初始化容量是16,也就是24,(1<<4,即1左移4位为二进制1000,即十进制16),源码注释中也指出“Must be a power of two”,也就是“必须是2的幂”,

  /**
     * The default initial capacity - MUST be a power of two.
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

但如果你new一个hashmap时指定的容量不是2的n次方呢?那么Hash会选择大于该数字的第一个2的幂作为容量。(1->2、7->8、9->16)

HashMap<String, String> ch = new HashMap<>(15);//大于15的第一个2的幂即16

那么为什么容量capacity必须是2的n次方呢?

因为hashMap为了存取高效,要尽量较少碰撞,就是要尽量把数据分配均匀,使得每个链表长度大致相同。关键就在于把当前数据存放到哪一个桶中(哪个节点node上),实现这个目标的算法就是取模运算。
但是,在计算机中,直接取模运算的效率不如位运算(&),什么是位运算?就是对于二进制数据的按位运算,1和1才得1,其他都得0,比如:1011 & 1100 = 1000,

sun公司的大牛们发现,当容量为2的n次方时,hash & (capacity - 1) == hash % capacity,于是就在源码中做了优化,通过 hash & (capacity - 1) 来替代取模运算,而前提就是容量必须为2的n次方。
假设:capacity:HashMap的容量(8,二进制为1000), hash:当前key的哈希值(1101), 取模运算为 hash % capacity,
为了方便,我们把这两个二进制取模运算转换为十进制再取模(不考虑二进制的符号位),则运算结果为13%8=5(0101),hash&(capacity-1)=0101(5),所以hash & (capacity - 1) == hash % capacity。

你可能感兴趣的:(Java基础学习)