【HashMap】为什么HashMap的大小一定要是2的幂次方呢?

        当我们put元素的时候, 首先会对key进行hash计算, 公式: (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

公式拆解:

        key等于null吗?等于返回0, 不等于返回 (h = key.hashCode()) ^ (h >>> 16)

        h = key.hashCode() 即 计算key的hashCode值, 赋值给h 

        h >>> 16 将h向右移16位

        (h = key.hashCode()) ^ (h >>> 16) 将key的hashCode值和移位后的hashCode值进行异或运算

        ps: hashCode()是一个本地方法, 我们看不到源码

        ps:异或运算: 异或运算法则为相同取0,不同取1 例: 3^10=9 即转成二进制 0011^1010 = 1001

 

 计算好hash值后, 会根据数组的长度和hash值进行与运算然后计算索引的位置

 通过上面两行代码我们知道了hashMap的索引位置是如何计算的, 下面我们回到正题, 为什么HashMap的大小一定要是2的幂次方呢?我们看一下resize()扩容方法;

 

 我们重点看一下do...while...这段代码, 从方法中可以看出,当hash值和原容器大小进行与运算等于0时,索引位置不变,当hash值和原容器大小进行与运算不等于0时, 索引位置=原索引位置+原容器大小. 这就是为什么hashMap的大小为什么一定要是2的幂次方. 如果容器大小不是2的幂次方, 扩容计算时就不会满足下面这段代码逻辑.因此map容器大小设置成2的幂次方可以简化扩容时的代码逻辑, 也大大提高了扩容时的性能.

 下面一段代码是我写的一个demo, 摘取了map的hash计算和索引计算的公式, 可以试着修改一下mapSize大小, 来看下一当mapSize不是2的幂次方的时候, 上面的逻辑是不通的, 如果索引位置没变可以试着多改几次验证看看

public class Demo {
    public static void main(String[] args) {
        //初始容量为8 改成16时索引未变, 改成32的时候会出现, 改成31 102的位置是17 不是3+16
        Integer mapSize = 30;
        //因为初始大小只有2, 所以a,c经过hash计算会存到一个索引1,链表下, b,d会存到一个索引0,链表下
        getIddex("102", mapSize);
        getIddex("103", mapSize);
        getIddex("114", mapSize);
        getIddex("115", mapSize);
    }

    /**
     * 计算索引位置
     * @param key
     * @param mapSize
     */
    private static void getIddex(String key, Integer mapSize) {
        int h;
        //计算hash值
        int hash =  (h = key.hashCode()) ^ (h >>> 16);
        System.out.println(key + "=====hash : " + hash);

        //根据mapSize和hash值计算索引
        int index = (mapSize - 1) & hash;
        System.out.println(key + "=====index : " + index);
        System.out.println("=========================================");
    }
}

最后, 希望此文章对大家有所帮助, 其中有任何问题欢迎随时指出, 欢迎大家共同探讨学习. 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值