HashMap关于容量的计算

在创建HashMap的时候可以通过构造函数指定初始容量,但实际在开辟空间时有时并不会按指定的容量大小去创建,而是按大于指定容量的2的次幂的最小值去创建

对应源码如下:

指定初始容量大小的构造方法会调初始容量大小、负载因子的构造方法,通过tableSizeFor(initialCapacity)方法调整大小

    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        //调整传入的容量大小
        this.threshold = tableSizeFor(initialCapacity);
    }
tableSizeFor方法如下:
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;
    }

其中 n |= n >>> 1 是 或等于 运算,即两个二进制数相同位上的都为0时 或等于 结果为0,其他情况为1;n >>> 1是向右移位操作,移出的数字被抛弃,空出的数字补零,数字是几就代表向右移几位,不用 >> 这种移位操作是为了保证移完位后位数与移位之前保持一致

为什么先减1再参与 或等于 运算?

目的是传入cap值为2的次幂时返回它本身,而不是大于它本身的最小的2的次幂。

如果不减1,比如传入8时,会返回16,但理论上应该返回8:

    public static void main(String[] args) {
        int cap = 8;
        //int n = cap - 1;
        int n = cap;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        System.out.println((n < 0) ? 1 : (n >= 1 << 30) ? 1 << 30 : n + 1);
    }

或等于 为什么要到 n >>> 16,而不是到 n >>> 32、n >>> 64?

因为容量的最大值 MAXIMUM_CAPACITY=1 << 30,即2的30次幂,30的一半是15,到 n >>> 16是为了保证极端情况下 或等于 操作结束后各二进制位全是1,最后 n+1 返回2的整数次幂。

简单演示下过程:

 

至于最大容量为什么定为2的30次幂,是因为容量是int类型数据,int占32位,Java的原始类型里没有无符号类型,(从右往左数)所以第32位表示符号位,1<<30即1向左移30位,1在第31位,其他位为0

为什么容量一定要调整成2的次幂大小呢?

简单来说,为的是 让容量-1 变成二进制时各位全为1,这样在和 hash 做 与运算 时会保留hash中 后 x 位的 1,从而保证元素的索引值不会超过数组长度。具体原因去问度娘吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值