在看这篇前需要了解以下几点
- HashMap里的键值数一旦大于阈值,就会进行扩容
- HashMap的底层数据结构是数组+链表+红黑树(JDK1.8)
- HashMap相同hash值,但是equals结果不相等的键值对会在同一条单向链表或红黑树中
所以问题来了,这里所说的键值数大于阈值,这个键值数只是单纯的指在数组中(链表头的键值对)的键值数,还是指包含所有链表下键值对的所有键值数。
以下跟进源码做个测试:
测试代码:
public class TestMain {
public static void main(String[] args) throws Exception {
HashMap<String, String> map = new HashMap<>(3);
map.put("1", "1");
map.put("Aa", "11");
map.put("BB", "66");
int beforeSize = map.size();
System.out.println(beforeSize);
map.put("2", "6");
int afterSize = map.size();
System.out.println(afterSize);
}
}
以上代码我初始容量设置为3,然后先向map里添加3条数据,其中key为Aa和BB的数据,他们的hash值是相同的,都是2112,所以这两条数据会在一个链表里,而之后再添加第4条数据,这时如果键值对数目为3,则需要扩容,如果键值对数目为2,则不会触发扩容操作。
直接找到判断扩容的代码,打上断点,这里的size就是我们要讨论的,而threshold就是阈值:
map.put(“1”, “1”)时,size原始值为0,++size,所以size变为1:
map.put(“Aa”, “11”)时,size原始值为1,++size,所以size变为2:
map.put(“BB”, “66”)时,发现"BB"的hashcode值和"Aa"一样,所以"BB"成为了"Aa"的下一个节点,二者组成了一个小型链表,但是"BB"的加入一样还是导致了++size,所以size变为3:
map.put(“2”, “6”)时,可以发现代码已经运行到了resize()方法,也就是扩容方法了,同时size也变成了4:
最后运行结果如下:
总结
通过如上代码运行和debug的参考,可以得出HashMap里的size属性指的就是键值总数,因为哪怕新加的元素和旧元素hash值相等而equals结果不同,会处于同一链表中,size一样会加一,而size大小最终决定了是否要进行扩容。