PUT过程

  1. public static void main(String[] args){
  2. HashMap map = new HashMap();
  3. map.put("java",10);//ok
  4. map.put("php",10);//ok
  5. map.put("java",20);//替换value
  6. System.out.println("map="+map);
  7. }
  8. 源码解析:
  9. 1. 执行构造器new HashMap,初始化加载因子(0.75),创建一个空数组HashMap$Node[] table = null
  10. public HashMap() {
  11. this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
  12. }
  13. 2. 执行put
  14. public V put(K key, V value) { //key = "java",value = 10
  15. return putVal(hash(key), key, value, false, true);
  16. }
  17. 2.1 key 进行hash 求值
  18. static final int hash(Object key) {
  19. int h;
  20. return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
  21. }
  22. 2.2
  23. final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
  24. boolean evict) {
  25. Node<K,V>[] tab; Node<K,V> p; int n, i; //辅助变量
  26. 如果底层的数组是为空,或者 length = 0 就扩容到16
  27. if ((tab = table) == null || (n = tab.length) == 0)
  28. n = (tab = resize()).length;
  29. 取出hash值对应的table 的索引位置的Node节点,如果为空,就直接把加入的数据直接放在当前node即可
  30. if ((p = tab[i = (n - 1) & hash]) == null)
  31. tab[i] = newNode(hash, key, value, null);
  32. else {
  33. Node<K,V> e; K k; 辅助变量
  34. // 如果table表的索引位置的key的hash值相同和新的key的hash值相同,并满足table现有的节点的key和准备准备添加的key是同一个对象,或者 equals返回真
  35. if (p.hash == hash &&
  36. ((k = p.key) == key || (key != null && key.equals(k))))
  37. e = p;
  38. else if (p instanceof TreeNode) //如果当前的table的已有的Node 是红黑树,就按照红黑树的方式处理
  39. e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
  40. else {
  41. //如果找到的节点,后面是链表,就循环比较
  42. for (int binCount = 0; ; ++binCount) {
  43. //如果整个链表,没有和他相同的,就加到该链表的最后
  44. if ((e = p.next) == null) {
  45. p.next = newNode(hash, key, value, null);
  46. //加入后,判断当前链表的个数,是否已经到8个,到8个,后就调用 treeifyBin 转为红黑树
  47. if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
  48. treeifyBin(tab, hash);
  49. break;
  50. }
  51. if (e.hash == hash && //如果在循环比较过程中,发现有相同的,就break,就只是替换value
  52. ((k = e.key) == key || (key != null && key.equals(k))))
  53. break;
  54. p = e;
  55. }
  56. }
  57. if (e != null) { // existing mapping for key
  58. V oldValue = e.value;
  59. if (!onlyIfAbsent || oldValue == null)
  60. e.value = value; //新值替换旧值
  61. afterNodeAccess(e);
  62. return oldValue;
  63. }
  64. }
  65. ++modCount;//每增加一个Node,就size ++
  66. if (++size > threshold) // threshold 第一次12,第二次24,第三次48.
  67. resize();
  68. afterNodeInsertion(evict);
  69. return null;
  70. }
  71. 转为红黑树
  72. 条件:1tablenull,或者大小还没有到64,暂时不树化,而是进行扩容
  73. 否则,才会真正的树化 -> 剪枝
  74. final void treeifyBin(Node<K,V>[] tab, int hash) {
  75. int n, index; Node<K,V> e;
  76. if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
  77. resize();
  78. ............
  79. }

扩容机制

node数组的大小大于8,并且map的size大于64才会去树化,
node 数组大于8,会扩容

table 数组大于12会扩容。

参考视频地址
https://www.bilibili.com/video/BV1YA411T76k?p=41&spm_id_from=pageDriver