• HashMap的put方法


    首先hashMap会根据传入的key值进行hash算法计算出hashcode,hashcode 就是桶值,然后查看桶是不是空的如果是空的就直接放进去,如果不是空的就看是不是红黑树,不是红黑树的话就是链表,将节点挂在链表后面,判断链表长度是否大于8,如果大于8就将这个链表树化。

    部分成员变量如下:
    //初始值,为16,必须为2的次幂
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;    
    //当容量被占满0.75时就需要reSize扩容
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    //链表长度到8,就转为红黑树
    static final int TREEIFY_THRESHOLD = 8;
    // 树大小为6,就转回链表
    static final int UNTREEIFY_THRESHOLD = 6;

    hashMap中有一个 Node<K, V> table 桶数组

    首先是hash算法:就是将key值和自己高16位异或运算。

    1 static final int hash(Object key) {
    2         int h;
    3         return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    4     }

    然后是调用putVal方法:

    1 public V put(K key, V value) {
    2         return putVal(hash(key), key, value, false, true);
    3     }

    putVal方法:

     1  final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
     2                    boolean evict) {
     3         HashMap.Node<K,V>[] tab; HashMap.Node<K,V> p; int n, i;
     4         //空表直接扩容
     5         if ((tab = table) == null || (n = tab.length) == 0)
     6             n = (tab = resize()).length;
     7         //n是扩容之后的数组长度,(n - 1) & hash = hash % n - 1
     8         //桶数组是空的,直接将节点放进去
     9         if ((p = tab[i = (n - 1) & hash]) == null)
    10             tab[i] = newNode(hash, key, value, null);
    11         else {
    12             //桶不是空的判断第一个节点是不是就是你要替换的那个节点
    13             HashMap.Node<K,V> e; K k;
    14             if (p.hash == hash &&
    15                     ((k = p.key) == key || (key != null && key.equals(k))))
    16                 e = p;//节点交换最后统一更换这个e节点的value
    17             //判断是不是树节点
    18             else if (p instanceof HashMap.TreeNode)
    19                 //调用红黑树的put方法,将替换后的节点返回
    20                 e = ((HashMap.TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
    21             else {
    22                 //最后就是链表
    23                 for (int binCount = 0; ; ++binCount) {
    24                     //遍历链表,找到一样的节点,如果遍历到最后就将节点放在链表最后面,
    25                     if ((e = p.next) == null) {
    26                         p.next = newNode(hash, key, value, null);
    27                         //节点放完之后,判断链表的长度打没达到树化的标准
    28                         if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
    29                             treeifyBin(tab, hash);//树化
    30                         break;
    31                     }
    32                     //找到节点
    33                     if (e.hash == hash &&
    34                             ((k = e.key) == key || (key != null && key.equals(k))))
    35                         break;
    36                     p = e;
    37                 }
    38             }
    39             //替换值,然后返回旧值
    40             if (e != null) { // existing mapping for key
    41                 V oldValue = e.value;
    42                 if (!onlyIfAbsent || oldValue == null)
    43                     e.value = value;
    44                 //空方法
    45                 afterNodeAccess(e);
    46                 return oldValue;
    47             }
    48         }
    49         ++modCount;
    50         //判断size值打没达到扩容的标准
    51         if (++size > threshold)
    52             resize();
    53         //一些空方法
    54         afterNodeInsertion(evict);
    55         return null;
    56     }

    简单的源码注释,越学越快乐!

  • 相关阅读:
    【bzoj1174】[Balkan2007]Toponyms Trie树
    【bzoj1786】[Ahoi2008]Pair 配对 dp
    【bzoj3956】Count 单调栈+可持久化线段树
    【bzoj4605】崂山白花蛇草水 权值线段树套KD-tree
    【bzoj3696】化合物 树形dp
    【bzoj1150】[CTSC2007]数据备份Backup 模拟费用流+链表+堆
    【bzoj3671】[Noi2014]随机数生成器 贪心
    【bzoj4653】[Noi2016]区间 双指针法+线段树
    【bzoj4197】[Noi2015]寿司晚宴 分解质因数+状态压缩dp
    用Python操作Named pipe命名管道,实用做法——os.read 或 os.write
  • 原文地址:https://www.cnblogs.com/frank9571/p/12287076.html
Copyright © 2020-2023  润新知