HashMap的长度为什么必须是2的N次方

我们看HashMap的源码可以知道,HashMap的长度强制为2的n次方

    static final int tableSizeFor(int cap) {
        int n = -1 >>> Integer.numberOfLeadingZeros(cap - 1);
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

    @HotSpotIntrinsicCandidate
    public static int numberOfLeadingZeros(int i) {
        // HD, Count leading 0's
        if (i <= 0)
            return i == 0 ? 32 : 0;
        int n = 31;
        if (i >= 1 << 16) { n -= 16; i >>>= 16; }
        if (i >= 1 <<  8) { n -=  8; i >>>=  8; }
        if (i >= 1 <<  4) { n -=  4; i >>>=  4; }
        if (i >= 1 <<  2) { n -=  2; i >>>=  2; }
        return n - (i >>> 1);
    }

那为什么HashMap的长度L需要是2的N次方呢?

往HashMap中存储一对k-v,那么要先计算key的hashcode,然后我们通过hashcode计算要把这个k-v存储到长度为L的数组的哪个位置

最简单的,我们可以通过模运算 hashcode%L 来计算存储的位置,但是模运算的效率相对较低,HashMap使用位运算(与运算)来计算存储的位置:hashcode&(L-1),这比模运算要快很多

比如长度L为16,hashcode是 ……1001,那么hashcode&(L-1)为1001&1111=1001=9,其实就是根据hashcode的最后四位来决定放到哪个桶里

如果长度L不为2的N次方,会怎么样呢?
比如长度L为10,任何一个hashcode和1001做与运算,都不可能等于0110,这样就会有几个位置,永远不可能存储到数据

hashcode和一个二进制数做与运算,如果这个二进制数的某一位为0,那么这一位与运算的结果永远不可能为1,也就是说,如果这个二进制数不是每一位都是1,那么一定会有一些结果永远不可能达到。所以这个二进制数的每一位都要是1,换成十进制这个数必须是2的N次方减1。

你可能感兴趣的:(HashMap的长度为什么必须是2的N次方)