HashMap源码已经在面试过程中,被问烂了,不过这里有太多细节了,我相信这个问题永不过时。不信,你来试试?
HashMap的几个概念
- 容量:大于初始容量参数的最小2次幂;
- 负载因子:HashMap扩容条件的一个参数,默认为0.75f;
- 阈值:容量与负载因子的乘积;
子涵提问
那么,你知道
new HashMap(16)
与new HashMap()
的初始阈值分别是多少吗?
实验工具类
public class HashMapTest {
public static void main(String[] args) throws Exception {
//指定初始容量15来创建一个HashMap
HashMap m = new HashMap(0);
//获取HashMap整个类
Class<?> mapType = m.getClass();
//获取指定属性,也可以调用getDeclaredFields()方法获取属性数组
Field threshold = mapType.getDeclaredField("threshold");
//将目标属性设置为可以访问
threshold.setAccessible(true);
//获取指定方法,因为HashMap没有容量这个属性,但是capacity方法会返回容量值
Method capacity = mapType.getDeclaredMethod("capacity");
//设置目标方法为可访问
capacity.setAccessible(true);
//打印刚初始化的HashMap的容量、阈值和元素数量
System.out.println("初始容量:" + capacity.invoke(m) + "初始阈值:" + threshold.get(m) + " 元素数量:" + m.size());
for (int i = 0; i < 17; i++) {
m.put(i, i);
//动态监测HashMap的容量、阈值和元素数量
System.out.println("容量:" + capacity.invoke(m) + " 阈值:" + threshold.get(m) + " 元素数量:" + m.size());
}
}
}
实验1:new HashMap(0)
初始容量:1 初始阈值:1 元素数量:0
容量:2 阈值:1 元素数量:1
容量:4 阈值:3 元素数量:2
容量:4 阈值:3 元素数量:3
容量:8 阈值:6 元素数量:4
容量:8 阈值:6 元素数量:5
容量:8 阈值:6 元素数量:6
容量:16 阈值:12 元素数量:7
容量:16 阈值:12 元素数量:8
容量:16 阈值:12 元素数量:9
容量:16 阈值:12 元素数量:10
容量:16 阈值:12 元素数量:11
容量:16 阈值:12 元素数量:12
容量:32 阈值:24 元素数量:13
容量:32 阈值:24 元素数量:14
容量:32 阈值:24 元素数量:15
容量:32 阈值:24 元素数量:16
容量:32 阈值:24 元素数量:17
实验2:new HashMap(3)
初始容量:4 初始阈值:4 元素数量:0
容量:4 阈值:3 元素数量:1
容量:4 阈值:3 元素数量:2
容量:4 阈值:3 元素数量:3
容量:8 阈值:6 元素数量:4
容量:8 阈值:6 元素数量:5
容量:8 阈值:6 元素数量:6
容量:16 阈值:12 元素数量:7
容量:16 阈值:12 元素数量:8
容量:16 阈值:12 元素数量:9
容量:16 阈值:12 元素数量:10
容量:16 阈值:12 元素数量:11
容量:16 阈值:12 元素数量:12
容量:32 阈值:24 元素数量:13
容量:32 阈值:24 元素数量:14
容量:32 阈值:24 元素数量:15
容量:32 阈值:24 元素数量:16
容量:32 阈值:24 元素数量:17
实验3:new HashMap()
初始容量:16 初始阈值:0 元素数量:0
容量:16 阈值:12 元素数量:1
容量:16 阈值:12 元素数量:2
容量:16 阈值:12 元素数量:3
容量:16 阈值:12 元素数量:4
容量:16 阈值:12 元素数量:5
容量:16 阈值:12 元素数量:6
容量:16 阈值:12 元素数量:7
容量:16 阈值:12 元素数量:8
容量:16 阈值:12 元素数量:9
容量:16 阈值:12 元素数量:10
容量:16 阈值:12 元素数量:11
容量:16 阈值:12 元素数量:12
容量:32 阈值:24 元素数量:13
容量:32 阈值:24 元素数量:14
容量:32 阈值:24 元素数量:15
容量:32 阈值:24 元素数量:16
容量:32 阈值:24 元素数量:17
源码解读
带参数的HashMap构造方法中,直接把容量赋值给了阈值。HashMap为啥这样做呢?
问题留下,供大家思考一下。
/**
* Constructs an empty <tt>HashMap</tt> with the specified initial
* capacity and load factor.
*
* @param initialCapacity the initial capacity
* @param loadFactor the load factor
* @throws IllegalArgumentException if the initial capacity is negative
* or the load factor is nonpositive
*/
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;
//带参数的HashMap构造方法中,直接把容量赋值给了阈值
this.threshold = tableSizeFor(initialCapacity);
}
结论
- 初始阈值(即当元素个数为0时):
– 当initialCapacity有值时,threshold 等于最大容量;
– 当initialCapacity没有值时,threshold为0,capacity为16; - 当元素不为0时,threshold均满足容量与负载因子的乘积。