云计算百科
云计算领域专业知识百科平台

HashMap保存一个key-value键值对的过程(对putVal()方法的解读)

首先需知HashMap的数据结构为:哈希表、链表、红黑树

向HashMap保存一个key-value键值对时重点使用putVal()方法

在putVal()方法中会定义:tab表示存入,p表示哈希表中已有

Node<K,V>[] tab; Node<K,V> p

  HashMap在存入一个值时,会先检查定义的HashMap的容量是否为0或null,如果是其中的一种可能,resize中有常量DEFAULT_INITIAL_CAPACITY,则将初始容量设定为16。

if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;

接下来会通过hash值来计算应存在哈希表中的下标位置,此下标位置如果在哈希表中的值为null,那么就将tab中的值存进newNode中(哈希值,key值,value值,next)。

if ((p = tab[i = (n – 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);

此下标位置不为空,如果有同样的哈希值且key的内容相同,或key不为空且key值已存在,则将旧的value值替换为新的value值。

else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;

此下标位置不为空且key不重复,则检查p是否存在红黑树中,在树中,则将键值对存入红黑树中。
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);

此下标位置不为空且key不重复,p不存在红黑树中,则判断当前下标的next是否为空,为空则将值存到next中,同时需要检查,添加新键值对后会不会产生红黑树,条件为此链表长度大于8且数组容量大于64,满足条件则产生红黑树,同时在链表中检查到的相同的key也进行替换操作。

else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD – 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}

同时在替换操作时,用新的value替换旧的value,可返回一个旧的value值oldValue

if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}

在putVal()方法的最后会使用resize方法用来达到存储过程中扩容的需求,每次扩容后的容量是扩容前的二倍,简单讲一下扩容条件:

第一种情况:在第一次存入值时将初始容量扩容为16,前面提到过。

第二种情况:在单条链表长度达到8且数组容量小于64时会扩容一次,避免红黑树轻易产生带来的维护成本。

第三种情况:HashMap中的元素个数超过threshold扩容阈值,threshold = 数组容量 * 加载因子。加载因子初始值为0.75,可自定义。

++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;

赞(0)
未经允许不得转载:网硕互联帮助中心 » HashMap保存一个key-value键值对的过程(对putVal()方法的解读)
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!