本文接上篇:
《HashMap最基本的实现流程(源码角度)》
前言
上篇主要说了HashMap的put操作实现的主流程,分析了源码中某些关键步骤之所以那样写的原因;对于一些分支流程没有过多展开,这里就填一下扩容的坑(注意:本文还是基于jdk1.7)
扩容
这里先把涉及到扩容的地方的源码贴一下:
void addEntry(int hash, K key, V value, int bucketIndex) {
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}
createEntry(hash, key, value, bucketIndex);
}
如上图代码,这是HashMap添加元素的函数,上一篇中我们假设还没到扩容的条件,先走了下面的主流程,这里我们就来看一下分支流程——扩容;
1. 扩容的条件
即什么时候会触发扩容?回答这个问题时这里可能会有一个误区(不怕笑话,我之前就是按误区这么想的),就是当 数组存的元素个数大于阈值的时候 会触发扩容,并且回答时脑海中浮现的比例图是下图:
其实直到我真的去看了HashMap的源码我才意识到我的错误。上一篇我一开始也特别强调了下size的含义;其实触发扩容的条件应该是这样的:当哈希表中存的元素个数(size:数组+链表存的元素)超过了阈值(threshold)时。
这样就对了嘛?对了一半,看源码中判断的条件,是一个且运算,即后面还有半句,这就表示并不是size>threshold时就会扩容,什么时候size>threshold但还不扩容呢?——当要存的下一个元素的索引并没有冲突时。如下图,假设现在的参数情况如下:
capacity=4(2^2)
loadfactor=0.75
threshold=capacity*loadFactor=3
size=3(满足扩容第一个条件)
存储情况如下图:
这时要添加的元素的索引被计算出来是3(或者2),因为此时2或者3的位置都没有元素(即tab