面试官:使用容量 10000 的HashMap 存9000条数据,会触发扩容吗 ?
先说结论,不会!
众所周知,Hashmap有负载因子为0.75,达到负载因子就会触发扩容,但这是无参构造即初始容量为16的Hashmap,而这里容量是10000,使用了有参构造的Hashmap,不一样。
1. 源码分析
在 HashMap 中,提供了一个指定初始容量的构造方法 HashMap(int initialCapacity),这个方法再通过 DEFAULT_LOAD_FACTOR 调用 HashMap 另一个重载的构造方法,初始化 loadFactor
为 0.75;
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
public HashMap(int initialCapacity, float loadFactor) {
......
this.loadFactor = loadFactor;
this.threshold = tableSizeFor(initialCapacity);;
构造方法初始化了两个成员变量 threshold
和 loadFactor
,其中 threshold 就是用来存储触发 HashMap 扩容的阈值,也就是说,当 HashMap 存储的数据量达到 threshold 时,就会触发扩容!
从构造方法中可以看出,threshold
并没有直接使用传入的 initialCapacity 作为扩容阈值,而是通过 tableSizeFor 方法处理后再赋值给 threshold。
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;
}
tableSizeFor 的作用就是寻找大于 initialCapacity 的 2 的整数次方,例如如果传入 10,经过 tableSizeFor 处理后返回 16,而此时传的是10000,10000并不是2的n次方倍,
如果从传进来参数是 10000作为initialCapacity ,实际上经过 tableSizeFor 方法处理之后,最终 threshold
就会变成 2 的 14 次幂 16384,再在 resize 方法中乘上负载因子 0.75,实际在不触发扩容的前提下,可存储的数据容量是 12288(16384 * 0.75),用来存放 9000条数据,不会触发扩容。
2. 总结
-
使用10000作为 initialCapacity 传入有参的HashMap构造方法,会调用重载的构造方法,初始化
loadFactor
和threhold
; -
threhold
就是扩容的阀值,即当HashMap的size达到阀值就会扩容; -
但是
threhold
不是直接将传入的参数 x 0.75,而是再调用 tableSizeFor来处理传入的参数,因为10000不是2的整数次方!所以10000 会变为2的14次方再 x 0.75,结果
threhold
大于10000,所以put 9000条数据不会触发扩容!
参考:
https://blog.csdn.net/Acx77/article/details/122692412
https://blog.csdn.net/qq_46548855/article/details/125900393
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/89163.html