HashMap在JDK1.8如何确定初始化容量

大家都知道HashMap是采用的懒加载机制,也就是说在你执行new HashMap()的时候,构造方法并没有在构造出HashMap实例的同时也把HashMap实例里所需的数组给初始化出来。

那么什么时候才去初始化里面的数组呢?答案只有在第一次需要用到这个数组的时候才会去初始化它,就是在你往HashMap里面put元素的时候。

而初始化数组时,它的容量是怎么确定的呢?有两种情况:
第一种是你在构造HashMap实例的时候,调用的是无参构造函数,此时默认的数组初始化长度就是16,在后续put元素初始化数组时生效。

    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }

第二种情况,则是你调的是带了数组容量参数的构造函数:

     public HashMap(int initialCapacity) {
            this(initialCapacity, DEFAULT_LOAD_FACTOR);
        }

或者

    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);
    }

当然可以看出上面那个构造方法里面执行的是this(initialCapacity, DEFAULT_LOAD_FACTOR),实际也就是下一个构造方法。

当你调用带参构造器初始化一个指定数组容量的HashMap时,构造器会根据你输入的参数重新计算得到一个HashMap初始化数组之后数组实际的长度,这个值也是会在put元素初始化数组时起作用。计算的逻辑在tableSizeFor(int cap)中:

    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;
    }

这个方法的作用是什么呢,比如你输入的容量参数为A,返回值为B,那么A与B的关系如下:
1、B大于或等于A
2、B为最接近A的一个2的n次方
举几个栗子就是:
1、输入1,返回1(2^0)
2、输入2,返回2(2^1)
3、输入3,返回4(2^2)
4、输入4,返回4(2^2)
5、输入5,返回8(2^3)
依此类推~

那么方法体是如何实现这些逻辑的呢,从代码中可以看到大部分代码都是在做无符号右移(>>>)和位或(|),这里其实都是在做2进制的位操作,描述起来比较困难,还是来举几个栗子吧,假如你输入的参数为35:
int n = cap - 1;
那么n = 34;
那么34对应的2进制编码为:100010
n | n >>> 1等同于n = n | n >>> 1,就是34与34右移一位之后做位或操作:
在这里插入图片描述
得到的二进制是110011,转化为10进制是51;

接下来n |= n >>> 2;
在这里插入图片描述
得到的二进制是111111,转化为10进制是63;

接下来是 n |= n >>> 4;
在这里插入图片描述
得到的二进制也是111111,转化为10进制是63;

接下来是 n |= n >>> 8;
在这里插入图片描述
得到的二进制也是111111,转化为10进制是63;

接下来是 n |= n >>> 16;
在这里插入图片描述
得到的二进制也是111111,转化为10进制是63;

最终 return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1这一行,
先判断n是否大于0:
1、不大于0返回1
2、否则再判断n是否大于定义的最大容量(1>>30):
1:若大于1>>30,则返回1>>30
2:否则返回n+1

实际最终这个方法,就是利用移位与位或运算,将n-1得到的值转成2进制之后,从1的最高位开始将低位全部转化为1,再加1之后就可以得到一个2^n的数~

  • 1
    点赞
  • 4
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:技术黑板 设计师:CSDN官方博客 返回首页
评论

打赏作者

insomsia

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值