HashMap的put方法源码深入分析【中】
现在要插入元素:
if里面是一个扩容的信息,判断条件是(size>=threshold)&&(null!=table[bucketIndex])
注意这个size是整个table数组里面有的Entey的数目,不是数组的长度
现在我们先不看扩容的代码先查看
createEntry(hash,key,value,bucketIndex):
参数:hash值,key,value,数组下标bucketIndex
这是我之前写的一个思路,和createEntry的思路差不多
再put一个Entry时
还以name:list;name2:lisi2为例
Entey<K,V>e=table[bucketIndex]
;table[bucketIndex]=name:lisi这个name:lisi赋值给e保存下来
然后:table[bucketIndext]=new Entry<>(hash,key,value,e)
;就是创建一个Entey然后指针指向e,此时table[bucketIndext]=name2:lisi2这个entry
现在我们来讨论扩容的情况:
当满足:判断条件(size>=threshold)&&(null!=table[bucketIndex])
时,就要开始扩容:
查看resize(int newCapacity),新的table的长度时原来数组长度的2倍
查看tansfer(newTable,initHashSeedAsNeeded(newCapacity)):
for(Entry<K,V> e:table)
是遍历数组:
while(null!=e)
是遍历链表,我们发现rehash是一个判断条件,这意味着,我们并不是一定要重新哈希,这一点俺还有点迷惑,下一篇你博客再写吧!嘻嘻
Entry<K,V>nexy=e.next;和e=next组合,向下遍历链表,直到为e=null
我们来看看
int i=indexFor(e.hash,newCapacity);
还记得这个方法吗?是h & (length-1);
假如一开始的长度是16:
15:0000 1111
h: 1010 1010
&
=:0000 1010
新的数组的长度是32:
31:0001 1111
h: 1010 1010
&
= :0000 1010
我们发现此时和再原来table的下标是相同的。
另外一种情况:
假如h:1011 1010
和15相与:
15:0000 1111
h: 1011 1010
&
=:0000 1010
和31相与:
31:0001 1111
h: 1011 1010
&
= : 0001 1010
我们发现下标为:原table的下标+原table的长度
总结:entry e在新的table数组的下标要么和原来的table数组的下标一样,要么是原table的下标+原table的长度
这样更有利于散列,有利于把长链表拆成短链表,而且当我们tansfer之后,我们的链表也倒置了。