HashMap之put get remove方法源码分析

注意一点:put时候去扩容 一是需要判断table是否为null  不为null的情况 去扩容 一是要达到阈值 而是要table长度要大于16

1.put(方法):

  //计算key值的hash 然后去做put

    public V put(K key, V value) {

        return putVal(hash(key), key, value, false, true);

    }

put过程:

       1.先去判断数组是不是为null  如果为null则初始化扩容

       2.计算出来的Hash存在的数组首节点是否为Null 如果为null则创建新node

       3.如果不为null 则表示发生了碰撞,先判断链首位是否相等(hash一样 key一样)(涉及到hashcode 和equls知识点)

          如果不等要去判断是不是树类型 如果是树类型 则以树的方式去put

          如果不是树的类型 则表示是链表 则在链表的尾部(判断最后一个节点为null)添加新节点

          如果相等并且判断当前节点数是否超过7了 ,如果超过7需要转化成树化

       4.如果这个key已经存在了 要去根据onlyIfAbsent属性来判断是否需要覆盖旧值

       5.如果加入了新节点 则需要改变表结构  modcount++

       hashmap节点个数+1,并判断是否超过阈值,如果超过则重建结构!

       final V putVal(int hash, K key, V value, boolean onlyIfAbsent,

                   boolean evict) {

        Node<K,V>[] tab; Node<K,V> p; int n, i;

        //table 为null  则去初始化 扩容

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

            //给table变量作初始化

            n = (tab = resize()).length;

        //如果该下标没有值  则创建个新node

        if ((p = tab[i = (n - 1) & hash]) == null)

            tab[i] = newNode(hash, key, value, null);

        else {

            //如果有值 发生碰撞

            Node<K,V> e; K k;

            //key  一样  刷新node

            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);

            // 3. 不是TreeNode类型,则表示是一个链表,这里就类似与jdk1.7中的操作

            else {

                for (int binCount = 0; ; ++binCount) {/// 遍历链表

                    // 在原来的node创建个新的node  p.next->new node

                    if ((e = p.next) == null) {//

                        p.next = newNode(hash, key, value, null);

                        ////  此时查找当前链表的次数已经超过7个,则需要链表RBT化!(变成红黑树类型)

                        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;

                }

            }

            // 如果e不为空,则表示在HashMap中找到了对应的节点

            if (e != null) { // existing mapping for key

                V oldValue = e.value;

                //// 当onlyIfAbsent=false 或者key对应的旧value为空时,用新的value替换旧value

                if (!onlyIfAbsent || oldValue == null)

                    e.value = value;

                afterNodeAccess(e);

                return oldValue;

            }

        }

        ++modCount;

        //// hashmap节点个数+1,并判断是否超过阈值,如果超过则重建结构!

        if (++size > threshold)

            resize();

        afterNodeInsertion(evict);

        return null;

    }

 

2.get(方法):

  //计算key值的hash 然后去做get

   public V get(Object key) {

        Node<K,V> e;

        return (e = getNode(hash(key), key)) == null ? null : e.value;

    }

get过程:

       /**

     * 1.先计算出hash值

     * 2.先去判断table是否为null并且链首位是否为null 如果为null 则直接返回Null

     * 3.先判断链首位的hash值和key是否相等 如果相等则直接返回

     * 4如果不相等 则去判断类型 如果为红黑树 则以红黑树的方式去查找

     * 5.如果不是红黑树 则以链表的形式循环查找

     * 6.找到直接返回 没有返回null

     */

    final Node<K,V> getNode(int hash, Object key) {

        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;

        //先是判断一通table是否为空以及根据hash找到存放的table数组的下标,并赋值给临时变量

        if ((tab = table) != null && (n = tab.length) > 0 &&

            (first = tab[(n - 1) & hash]) != null) {

            ////总是先检查数组下标第一个节点是否满足key,满足则返回

            if (first.hash == hash && // always check first node

                ((k = first.key) == key || (key != null && key.equals(k))))

                return first;

            ///如果第一个与key不相等,则循环查看桶

            if ((e = first.next) != null) {

                //检查是否为树节点,是的话采用树节点的方法来获取对应的key的值

                if (first instanceof TreeNode)

                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);

                do {

                   //do-while循环判断,直到找到为止

                    if (e.hash == hash &&

                        ((k = e.key) == key || (key != null && key.equals(k))))

                        return e;

                } while ((e = e.next) != null);

            }

        }

        return null;

    }

3.remove(方法):

//计算key值的hash 然后去做remove

public V remove(Object key) {

        Node<K,V> e;

        return (e = removeNode(hash(key), key, null, false, true)) == null ?

            null : e.value;

    }

/**

     * 1.先去看table是否为null  链首位是否为null 如果为null  直接返回null

     * 2.先判断链首位是否key hash都相等 如果相等 找到该节点

     * 3.如果不等 去判断是否为红黑树类型 如果是 则以红黑树的方式找到该节点

     * 4.如果不是红黑树类型 则循环链表找到该节点

     * 5.如果找到了该节点 则去作删除动作(两种不同的删除方式 以红黑树的方式去删除(红黑树如果小于6阈值 要转换成链表))

     * 6.modcount++  表length-1

     */

    final Node<K,V> removeNode(int hash, Object key, Object value,

                               boolean matchValue, boolean movable) {

 

        Node<K,V>[] tab; Node<K,V> p; int n, index;

        ////老规矩,还是先判断table是否为空之类的逻辑,注意赋值操作

        if ((tab = table) != null && (n = tab.length) > 0 &&

            (p = tab[index = (n - 1) & hash]) != null) {

            Node<K,V> node = null, e; K k; V v;

            if (p.hash == hash &&

                ((k = p.key) == key || (key != null && key.equals(k))))

                node = p;

            else if ((e = p.next) != null) {

                if (p instanceof TreeNode)

                    node = ((TreeNode<K,V>)p).getTreeNode(hash, key);

                else {

                    do {

                        if (e.hash == hash &&

                            ((k = e.key) == key ||

                             (key != null && key.equals(k)))) {

                            node = e;

                            break;

                        }

                        p = e;

                    } while ((e = e.next) != null);

                }

            }

            //找到相应节点 作删除动作

            if (node != null && (!matchValue || (v = node.value) == value ||

                                 (value != null && value.equals(v)))) {

                if (node instanceof TreeNode)

                    ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);

                ///如果p == node,说明该key所在的位置为数组的下标位置,所以下标位置指向下一个节点即可

                else if (node == p)

                    tab[index] = node.next;

                else

                    //否则的话,key在桶中,p为node的上一个节点,p.next指向node.next即可

                    p.next = node.next;

                ++modCount;

                --size;

                afterNodeRemoval(node);

                return node;

            }

        }

        return null;

    }

 

 

学习资料:

https://blog.csdn.net/qq_28523617/article/details/77533097

http://www.cnblogs.com/PoorGuy/p/10397346.html

http://www.cnblogs.com/bruceChan0018/p/8033897.html

https://blog.csdn.net/crazy1235/article/details/75579654

https://www.cnblogs.com/finite/p/8251587.html

 

posted @ 2020-05-25 10:52  我是张某某  阅读(356)  评论(0)    收藏  举报