共同学习Java源代码-数据结构-HashMap(六)

来源:互联网 发布:win10手写识别软件 编辑:程序博客网 时间:2024/06/11 04:57
    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);

    }

这个方法也是非常常用的put方法 调用的是下面的putVal方法 将键的哈希值 键 以及两个布尔参数传到下面的方法里 第一个布尔值为false表示添加的键值如果存在就覆盖 第二个为true代表不是creation模式 第二个参数什么意思真不清楚 听说HashMap里用不上这个参数

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            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;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

首先创建临时变量 节点数组类型的tab 节点类型的p int类型的n i

将哈希桶数组赋给tab 判断tab为空或tab的长度为空 也就是哈希桶数组没有元素

调用resize方法创建一个新的哈希桶数组赋给tab 将新哈希桶数组的长度赋给n

再将(n - 1) & hash值赋给i 找到i对应的哈希桶数组元素 也就是该键的哈希值对应的桶的第一个元素 如果这个第一个元素为空 就创建一个新节点 将键值对放入这个新节点

如果该桶元素对应的链表的首节点不为空 那就继续以下的操作

创建临时变量节点类型的e和键类型k 

判断如果桶元素 也就是链表的起点元素的键和传入的键相等或为同一对象 那么就将这个链表的首元素赋给e

判断如果链表已经升级成了树 也就是链表元素超过了8 调用树对象的putTreeVal方法将键值对添加进去

如果哈希桶收元素的键和要添加的键不一样 且链表尚未升级成树 就进入一个无休止的for循环 循环变量为binCount 进入循环后 先遍历链表找到一个空节点 新建节点 然后判断binCount循环了多少次 一旦超过链表变成树的阈值 则调用treeify方法将链表升级成树 并终止循环

然后判断遍历中的节点的键是否和要添加的键相等或为同一对象 如果是 就将e赋值为该节点 然后中止循环

循环结束后 判断e是否为空 如果e不为空说明链表中已经有了该键的节点 判断如果onliIfAbsent为false 也就是覆盖添加 或者该节点值为空 就将新的值替换为旧的值 然后将旧的值返回 

 afterNodeAccess(e);为空方法 HashMap未予以实现

然后将modCount自增 代表修改次数加一 

再判断如果size也就是整个键值对总数自增后超过了哈希桶扩容的阈值 则调用resize方法将哈希桶扩容

afterNodeInsertion(evict);为空方法实现

最后返回空 也就是之前不存在这个键值对的情况下进行添加






阅读全文
0 0