常见方法源码分析:HashMap的put(K k,V v)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了常见方法源码分析:HashMap的put(K k,V v)相关的知识,希望对你有一定的参考价值。
version:JDK1.8
一.调用内部的另一个方法:
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict)
将结果直接返回
源码:
1 public V put(K key, V value) { 2 return putVal(hash(key), key, value, false, true); 3 }
二.那么进入putVal这个方法看看内部是怎么实现的
注:当前对象就是需要插入的HashMap对象
1.首先声明了四个变量
1 Node<K, V>[] tab; //当前对象HashMap中的所有键值对Node对象数组 2 Node<K, V> p; //传入key在当前对象中对应的Node对象 3 int n; //当前对象内部Node的数量 4 int i; //传入ley在当前对象中对应的Node对象的数组下标
2.判断当前对象是否为null或者内部没有Node,
如果是,那么给当前对象初始化一下,并且对tab和n进行赋值
1 if ((tab = table) == null || (n = tab.length) == 0) 2 n = (tab = resize()).length;
3.判断key对应的Node在当前对象中是否存在
-> 如果不存在,那么新建一个Node,并插入到对应的Node数组中
1 if ((p = tab[i = (n - 1) & hash]) == null) 2 tab[i] = newNode(hash, key, value, null);
其中的newNode方法如下:
1 Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) { 2 return new Node<>(hash, key, value, next); 3 }
-> 如果存在
1).声明两个变量:
1 Node<K, V> e; 2 K k;
2).进行判断,key值在当前对象中对应的Node的hash值和key是否一样
--> 一致
将p赋值给e
1 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) 3 e = p;
--> 不一致,说明当前的HashMap中已经存在一个Node占了这个坑,继续判断占坑的Node是否为TreeNode:
--> 属于TreeNode,那么进行转换:
1 else if (p instanceof TreeNode) 2 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
--> 不属于,那么就需要把这个坑里的所有Node都拿出来,看看有没有和传入的key和hash值一样的
开始循环,知道最后一个对比结束或者找到了和传入的hash值和key一样的Node
到最后也没有找到node的话,生成一个新的node,
后面的操作不明白,等以后知道再编辑修改
1 for (int binCount = 0; ; ++binCount) { 2 if ((e = p.next) == null) { 3 p.next = newNode(hash, key, value, null); 4 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st 5 treeifyBin(tab, hash); 6 break; 7 } 8 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) 10 break; 11 p = e; 12 }
最后判断是否找到了这个node,如果找到了,取出这个node原来的value
如果需要替换或者原来的node中的value是为null的,那么把传入的value赋值给这个node
最后把原来的value值返回,方法结束
1 if (e != null) { // existing mapping for key 2 V oldValue = e.value; 3 if (!onlyIfAbsent || oldValue == null) 4 e.value = value; 5 afterNodeAccess(e); 6 return oldValue; 7 }
里面的afterNodeAccess(e),并没有进行任何操作:
1 // Callbacks to allow LinkedHashMap post-actions 2 void afterNodeAccess(Node<K,V> p) { }
最后,map的修改次数++,若是map的长度和原来的不一致,也重新设定长度,执行到这里,说明之前并没有成功插入,那么返回null:
1 ++modCount; 2 if (++size > threshold) 3 resize(); 4 afterNodeInsertion(evict); 5 return null;
最后,完整的源码如下:
1 final V putVal(int hash, K key, V value, boolean onlyIfAbsent, 2 boolean evict) { 3 Node<K,V>[] tab; Node<K,V> p; int n, i; 4 if ((tab = table) == null || (n = tab.length) == 0) 5 n = (tab = resize()).length; 6 if ((p = tab[i = (n - 1) & hash]) == null) 7 tab[i] = newNode(hash, key, value, null); 8 else { 9 Node<K,V> e; K k; 10 if (p.hash == hash && 11 ((k = p.key) == key || (key != null && key.equals(k)))) 12 e = p; 13 else if (p instanceof TreeNode) 14 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); 15 else { 16 for (int binCount = 0; ; ++binCount) { 17 if ((e = p.next) == null) { 18 p.next = newNode(hash, key, value, null); 19 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st 20 treeifyBin(tab, hash); 21 break; 22 } 23 if (e.hash == hash && 24 ((k = e.key) == key || (key != null && key.equals(k)))) 25 break; 26 p = e; 27 } 28 } 29 if (e != null) { // existing mapping for key 30 V oldValue = e.value; 31 if (!onlyIfAbsent || oldValue == null) 32 e.value = value; 33 afterNodeAccess(e); 34 return oldValue; 35 } 36 } 37 ++modCount; 38 if (++size > threshold) 39 resize(); 40 afterNodeInsertion(evict); 41 return null; 42 }
最后:
编写源码的人的喜欢把赋值写在判断中的风格有点接受不能
以上是关于常见方法源码分析:HashMap的put(K k,V v)的主要内容,如果未能解决你的问题,请参考以下文章