HashMap源码分析之另外一部分数据操作相关方法

删除数据
public V remove(Object key)

final Node<K,V> removeNode(int hash, Object key, Object value, boolean matchValue, boolean movable)

/**
     * Removes the mapping for the specified key from this map if present.
     *
     * @param  key key whose mapping is to be removed from the map
     * @return the previous value associated with <tt>key</tt>, or
     *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
     *         (A <tt>null</tt> return can also indicate that the map
     *         previously associated <tt>null</tt> with <tt>key</tt>.)
     */
    public V remove(Object key) {
        Node<K,V> e;
        return (e = removeNode(hash(key), key, null, false, true)) == null ?
            null : e.value;
    }

    /**
     * Implements Map.remove and related methods.
     *
     * @param hash hash for key
     * @param key the key
     * @param value the value to match if matchValue, else ignored
     * @param matchValue if true only remove if value is equal
     * @param movable if false do not move other nodes while removing
     * @return the node, or null if none
     */
    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不为空,并且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;
            //判断key对应的key值是否正确且不为空,是的话赋值给node
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                node = p;
            else if ((e = p.next) != null) {
            //判断当前是否树化,如树化,getTreeNode获得对应节点。
                if (p instanceof TreeNode)
                    node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
                else {
                    do {
                    //如果没树化,是链表就遍历链表找到对应的key的节点,赋值给node
                        if (e.hash == hash &&
                            ((k = e.key) == key ||
                             (key != null && key.equals(k)))) {
                            node = e;
                            break;
                        }
                        p = e;
                    } while ((e = e.next) != null);
                }
            }
            //判断node是否为空,并且对应的值是否相等,如果树化了就调用removeTreeNode移除树的节点。
            //如果key在当前tab的索引位置,直接覆盖,否则p.next = node.next移除node
            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);
                else if (node == p)
                    tab[index] = node.next;
                else
                    p.next = node.next;
                ++modCount;
                --size;
                afterNodeRemoval(node);
                return node;
            }
        }
        return null;
    }

afterNodeRemoval方法默认是空实现

// Callbacks to allow LinkedHashMap post-actions
void afterNodeAccess(Node<K,V> p) { }
void afterNodeInsertion(boolean evict) { }
void afterNodeRemoval(Node<K,V> p) { }

TreeNode
继承LinkedHashMap.Entry<K,V>,而后者又继承了Hashmap.Node<K,V>。所以TreeNode有Node属性,并且由于添加了prev这个前驱指针使得链表变成双向的。

TreeNode<K,V> root()

/**
     * Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn
     * extends Node) so can be used as extension of either regular or
     * linked node.
     */
    static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
        //父节点,左、右节点删除后断开连接,red:是否是红黑树的红节点
        TreeNode<K,V> parent;  // red-black tree links
        TreeNode<K,V> left;
        TreeNode<K,V> right;
        TreeNode<K,V> prev;    // needed to unlink next upon deletion
        boolean red;
        TreeNode(int hash, K key, V val, Node<K,V> next) {
            super(hash, key, val, next);
        }
        //这里是LinkedHashMap里Entry<K,V>
    static class Entry<K,V> extends HashMap.Node<K,V> {
        Entry<K,V> before, after;
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }
//返回根节点,检查parent是否为null,为null就是根节点。
        /**
         * Returns root of tree containing this node.
         */
        final TreeNode<K,V> root() {
            for (TreeNode<K,V> r = this, p;;) {
                if ((p = r.parent) == null)
                    return r;
                r = p;
            }
        }

getTreeNode
第2行p赋值当前节点,从当前节点开始查找,变量ph是当前节点的hash,变量dir是Comparable接口的比较结果变量pl当前节点的左节点,变量pr当前节点的右节点,变量q是右节点查找时候的返回值,如果找到了返回找到的节点

参数h是TreeNode的hash,而hash就是保持平衡二叉树的字段,通过它进行比较,小的放左边,大的放右边
参数k是要查找的节点的key
参数kc是要查找节点实现的key的运行时类型

		final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
		//当前对象
            TreeNode<K,V> p = this;
            do {
                int ph, dir; K pk;
               //当前对象的hash值,方向,键对象 
                TreeNode<K,V> pl = p.left, pr = p.right, q;//左右孩子及q:存储并返回找到的对象
                //如果当前节点的hash值大于k的hash值,左孩子赋值给p,
                //如果小于,右孩子赋值给p,
                //如果相等,并且当前节点的键对象pk和k相等,返回当前节点。
                if ((ph = p.hash) > h)
                    p = pl;
                else if (ph < h)
                    p = pr;
                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
                    return p;
                    //如果左孩子为空,右孩子赋值给p
                    //如果右孩子为空,左孩子赋值给p
                    
                else if (pl == null)
                    p = pr;
                else if (pr == null)
                    p = pl;
                    //如果左右孩子都不为空,通过key实现的comparable比较。comparableClassFor是获取k的运行时类型。
                    //compareComparables方法先判断,key与运行时kc是同类型,在通过调用k和kc实现的Comparable接口的compareTo进行比较
                else if ((kc != null ||
                          (kc = comparableClassFor(k)) != null) &&
                         (dir = compareComparables(kc, k, pk)) != 0)
                    p = (dir < 0) ? pl : pr;
                else if ((q = pr.find(h, k, kc)) != null)
                    return q;
                    //如果均不满足,右节点递归比较找到且返回,找不到就将左孩子赋值给p,进入下回循环在比较
                else
                    p = pl;
            } while (p != null);
            return null;
        }
//先找到根节点然后调用find()方法,parent如果为空,表示现在的节点是root
		final TreeNode<K,V> getTreeNode(int h, Object k) {
            return ((parent != null) ? root() : this).find(h, k, null);
        }

final void treeify(Node<K,V>[] tab)双向链表变为红黑树
final Node<K,V> untreeify(HashMap<K,V> map)树转链表

		/**
         * Forms tree of the nodes linked from this node.
         */
        final void treeify(Node<K,V>[] tab) {
         //构建数的根节点
            TreeNode<K,V> root = null;
            //x指向当前节点,遍历链表
            for (TreeNode<K,V> x = this, next; x != null; x = next) {
            //下一个节点
            //节点的左右节点均为空
                next = (TreeNode<K,V>)x.next;
                x.left = x.right = null;
                //如果根节点为空
                if (root == null) {
                //当前节点的父节点赋值为空,红属性为false即此节点为黑,根节点指向当前节点
                    x.parent = null;
                    x.red = false;
                    root = x;
                }
                //如果存在根节点,取得当前链表节点的key、hash值
                else {
                    K k = x.key;
                    int h = x.hash;
                    //定义key所属的class
                    Class<?> kc = null;
                    //从根节点开始遍历
                    for (TreeNode<K,V> p = root;;) {
                        int dir, ph;
                        K pk = p.key;
                        //如果当前节点hash值大于链表节点的hash值,当前链表节点指当前树节点的左侧
                        if ((ph = p.hash) > h)
                            dir = -1;
                        else if (ph < h)
                        //右侧
                            dir = 1;
                            //如果两节点key、hash值相等,进行comparable比较,若相等进行tieBreakOrder比较
                   
                        else if ((kc == null &&
                                  (kc = comparableClassFor(k)) == null) ||
                                 (dir = compareComparables(kc, k, pk)) == 0)
                            dir = tieBreakOrder(k, pk);
//保存当前数节点
                        TreeNode<K,V> xp = p;
                        
                /*
                 * 如果dir <= 0 当前链表节点一定放置在当前树节点的左侧,
                 * 但不一定是该树节点的左孩子,也可能是左孩子的右孩子 或者 更深层次的节点。
                 * 如果dir > 0 当前链表节点一定放置在当前树节点的右侧,
                 * 但不一定是该树节点的右孩子,也可能是右孩子的左孩子 或者 更深层次的节点。
                 * 如果当前树节点不是叶子节点,那么最终会以当前树节点的左孩子或者右孩子 为 起始节点 
                 *  再从 根节点遍历 处开始 重新寻找自己(当前链表节点)的位置
                 * 如果当前树节点就是叶子节点,那么根据dir的值,就可以把当前链表节点挂载到当前树节点的左或者右侧了。
                 * 挂载之后,还需要重新把树进行平衡。平衡之后,就可以针对下一个链表节点进行处理了。
				 */
                        if ((p = (dir <= 0) ? p.left : p.right) == null) {
                        //当前链表的节点做当前树节点的子节点
                            x.parent = xp;
                            if (dir <= 0)
                                xp.left = x;
                            else
                                xp.right = x;
                                //重新平衡
                            root = balanceInsertion(root, x);
                            break;
                        }
                    }
                }
            }
            moveRootToFront(tab, root);
        }

        /**
         * Returns a list of non-TreeNodes replacing those linked from
         * this node.
         */
        final Node<K,V> untreeify(HashMap<K,V> map) {
            Node<K,V> hd = null, tl = null;
            for (Node<K,V> q = this; q != null; q = q.next) {
                Node<K,V> p = map.replacementNode(q, null);
                if (tl == null)
                    hd = p;
                else
                    tl.next = p;
                tl = p;
            }
            return hd;
        }

final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab, int h, K k, V v) 插入数据、
final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab, boolean movable) 移除数据

      /**
         * Tree version of putVal.
         */
        final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,
                                       int h, K k, V v) {
            Class<?> kc = null;
            boolean searched = false;
            TreeNode<K,V> root = (parent != null) ? root() : this;
            for (TreeNode<K,V> p = root;;) {
                int dir, ph; K pk;
                //比较hash值的大小,大于或者小于则查找子树,相等直接返回
                if ((ph = p.hash) > h)
                    dir = -1;//左
                else if (ph < h)
                    dir = 1;//右
                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
                    return p;
                else if ((kc == null &&
                          (kc = comparableClassFor(k)) == null) ||
                         (dir = compareComparables(kc, k, pk)) == 0) {
                    if (!searched) {
                        TreeNode<K,V> q, ch;
                        searched = true;
                        if (((ch = p.left) != null &&
                             (q = ch.find(h, k, kc)) != null) ||
                            ((ch = p.right) != null &&
                             (q = ch.find(h, k, kc)) != null))
                            return q;
                    }
                    dir = tieBreakOrder(k, pk);
                }
//根据比较的hash值的大小的结果更新p为左孩子还是右孩子
                TreeNode<K,V> xp = p;
                if ((p = (dir <= 0) ? p.left : p.right) == null) {
                    Node<K,V> xpn = xp.next;
                    TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);
                    if (dir <= 0)
                        xp.left = x;
                    else
                        xp.right = x;
                    xp.next = x;
                    x.parent = x.prev = xp;
                    if (xpn != null)
                        ((TreeNode<K,V>)xpn).prev = x;
                    moveRootToFront(tab, balanceInsertion(root, x));
                    return null;
                }
            }
        }

        /**
         * Removes the given node, that must be present before this call.
         * This is messier than typical red-black deletion code because we
         * cannot swap the contents of an interior node with a leaf
         * successor that is pinned by "next" pointers that are accessible
         * independently during traversal. So instead we swap the tree
         * linkages. If the current tree appears to have too few nodes,
         * the bin is converted back to a plain bin. (The test triggers
         * somewhere between 2 and 6 nodes, depending on tree structure).
         */
        final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab,
                                  boolean movable) {
            int n;
            //tab为空,根节点为空,树的数量少转为链表,返回null,
            if (tab == null || (n = tab.length) == 0)
                return;
            int index = (n - 1) & hash;
            TreeNode<K,V> first = (TreeNode<K,V>)tab[index], root = first, rl;
            TreeNode<K,V> succ = (TreeNode<K,V>)next, pred = prev;
            if (pred == null)
                tab[index] = first = succ;
            else
                pred.next = succ;
            if (succ != null)
                succ.prev = pred;
            if (first == null)
                return;
            if (root.parent != null)
                root = root.root();
            if (root == null
                || (movable
                    && (root.right == null
                        || (rl = root.left) == null
                        || rl.left == null))) {
                tab[index] = first.untreeify(map);  // too small
                return;
            }
           
            TreeNode<K,V> p = this, pl = left, pr = right, replacement;
             //寻找要替换的点
            if (pl != null && pr != null) {
                TreeNode<K,V> s = pr, sl;
                while ((sl = s.left) != null) // find successor
                    s = sl;
                boolean c = s.red; s.red = p.red; p.red = c; // swap colors
                TreeNode<K,V> sr = s.right;
                TreeNode<K,V> pp = p.parent;
                
                if (s == pr) { // p was s's direct parent
                    p.parent = s;
                    s.right = p;
                }
                else {
                    TreeNode<K,V> sp = s.parent;
                    if ((p.parent = sp) != null) {
                        if (s == sp.left)
                            sp.left = p;
                        else
                            sp.right = p;
                    }
                    if ((s.right = pr) != null)
                        pr.parent = s;
                }
                p.left = null;
                if ((p.right = sr) != null)
                    sr.parent = p;
                if ((s.left = pl) != null)
                    pl.parent = s;
                if ((s.parent = pp) == null)
                    root = s;
                else if (p == pp.left)
                    pp.left = s;
                else
                    pp.right = s;
                if (sr != null)
                    replacement = sr;
                else
                    replacement = p;
            }
            else if (pl != null)
                replacement = pl;
            else if (pr != null)
                replacement = pr;
            else
                replacement = p;
                //如果要移除的不是这个TreeNode,则替换当前节点的父节点或者左右节点
            if (replacement != p) {
                TreeNode<K,V> pp = replacement.parent = p.parent;
                if (pp == null)
                    root = replacement;
                else if (p == pp.left)
                    pp.left = replacement;
                else
                    pp.right = replacement;
                p.left = p.right = p.parent = null;
            }
//如果是黑树就调用balanceDeletion方法实现平衡
            TreeNode<K,V> r = p.red ? root : balanceDeletion(root, replacement);
//如果要移除得是当前TreeNode则从树中移除当前节点
            if (replacement == p) {  // detach
                TreeNode<K,V> pp = p.parent;
                p.parent = null;
                if (pp != null) {
                    if (p == pp.left)
                        pp.left = null;
                    else if (p == pp.right)
                        pp.right = null;
                }
            }
            if (movable)
                moveRootToFront(tab, r);
        }

  

final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit)将红黑树拆成两个链表,(扩容原因导致原本在一个数组元素下的Node节点分为高低位两部分)再根据链表长度决定树化或链表化


        /**
         * Splits nodes in a tree bin into lower and upper tree bins,
         * or untreeifies if now too small. Called only from resize;
         * see above discussion about split bits and indices.
         *
         * @param map the map
         * @param tab the table for recording bin heads
         * @param index the index of the table being split
         * @param bit the bit of hash to split on
         */
        final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
            TreeNode<K,V> b = this;
            //拆成两个链表
            // Relink into lo and hi lists, preserving order
            TreeNode<K,V> loHead = null, loTail = null;
            TreeNode<K,V> hiHead = null, hiTail = null;
            int lc = 0, hc = 0;
            
            for (TreeNode<K,V> e = b, next; e != null; e = next) {
                next = (TreeNode<K,V>)e.next;
                e.next = null;
                //当前节点hash值与bit(数值是扩容前的容量大小)位运算
                if ((e.hash & bit) == 0) {
                //0说明在低位树,即为原位置
                    if ((e.prev = loTail) == null)
                        loHead = e;
                    else
                        loTail.next = e;
                    loTail = e;
                    ++lc;
                }
                else {
                //同上,高位树
                    if ((e.prev = hiTail) == null)
                        hiHead = e;
                    else
                        hiTail.next = e;
                    hiTail = e;
                    ++hc;
                }
            }
//对高低位树处理,将数组节点指向树根节点或者链表首节点
            if (loHead != null) {
            //与非树化阈值比较
                if (lc <= UNTREEIFY_THRESHOLD)
                //转换成链表结构
                    tab[index] = loHead.untreeify(map);
                else {
                    tab[index] = loHead;
                    //如果高位树为空
                    //表示节点全在低位树,不需要再进行树化(已树化)
                    if (hiHead != null) // (else is already treeified)
                        loHead.treeify(tab);
                }
            }
            if (hiHead != null) {
                if (hc <= UNTREEIFY_THRESHOLD)
                    tab[index + bit] = hiHead.untreeify(map);
                else {
                //设置高位树位置:原本位置+旧数组大小(bit)
                    tab[index + bit] = hiHead;
                    if (loHead != null)
                        hiHead.treeify(tab);
                }
            }
        }

发布了26 篇原创文章 · 获赞 4 · 访问量 2387

猜你喜欢

转载自blog.csdn.net/weixin_43257196/article/details/103587598