jdk8 hashmap纯源码分析

package arraylist;

import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * 一般将数组中的每一个元素称作桶(segment),桶中连的链表或者红黑树中的每一个元素成为bin
 * <p>
 * 底层实现:数组 + 单向链表 + 红黑树
 * <p>
 * 红黑树定义和性质
 * 红黑树是一种含有红黑结点并能自平衡的二叉查找树。它必须满足下面性质:
 * <p>
 * 性质1:每个节点要么是黑色,要么是红色。
 * 性质2:根节点是黑色。
 * 性质3:每个叶子节点(NIL)是黑色。
 * 性质4:每个红色结点的两个子结点一定都是黑色。
 * 性质5:任意一结点到每个叶子结点的路径都包含数量相同的黑结点。
 * <p>
 * 从性质5又可以推出:
 * 性质5.1:如果一个结点A存在黑子结点,那么该结点A肯定有两个子结点
 * <p>
 * 红黑树自平衡的三种操作:左旋、右旋和变色
 * 左旋:以某个结点作为支点(旋转结点),其右子结点变为旋转结点的父结点,右子结点的左子结点变为旋转结点的右子结点,左子结点保持不变。
 * 右旋:以某个结点作为支点(旋转结点),其左子结点变为旋转结点的父结点,左子结点的右子结点变为旋转结点的左子结点,右子结点保持不变。
 * 变色:结点的颜色由红变黑或由黑变红1。
 *
 * @param <K>
 * @param <V>
 */
public class HashMap源码分析<K, V> {

    //默认初始化容量 16。容量必须为2的次方。默认的hashmap大小为16
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;

    static final int MAXIMUM_CAPACITY = 1 << 30;

    //默认加载因子
    //即实际数量超过总数DEFAULT_LOAD_FACTOR的数量即会发生resize动作
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    //树化阈值 8。当单个segment的容量超过阈值时,将链表转化为红黑树
    static final int TREEIFY_THRESHOLD = 8;

    //链表化阈值 6。当resize后或者删除操作后单个segment的容量低于阈值时,将红黑树转化为链表
    static final int UNTREEIFY_THRESHOLD = 6;

    //最小树化容量 64。当桶中的bin被树化时最小的hash表容量,低于该容量时不会树化
    static final int MIN_TREEIFY_CAPACITY = 64;

    //底层维护了一个table存放Node节点
    transient Node<K, V>[] table;

    transient Set<Map.Entry<K, V>> entrySet;

    transient int size;

    transient int modCount; //fast-fail

    //装载因子:用来衡量HashMap满的程度。loadFactor的默认值为0.75f。
    //计算HashMap的实时装载因子的方法为:size/capacity,而不是占用桶的数量去除以capacity
    final float loadFactor;

    //扩容阈值:当HashMap的size值大于threshold时会执行resize操作
    int threshold;

    public HashMap源码分析() {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
    }

    public HashMap源码分析(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

    public HashMap源码分析(int initialCapacity, float loadFactor) {
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }

    //单向链表
    static class Node<K, V> implements Map.Entry<K, V> {
        final int hash;
        final K key;
        V value;
        Node<K, V> next;

        Node(int hash, K key, V value, Node<K, V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public final K getKey() {
            return key;
        }

        public final V getValue() {
            return value;
        }

        public final String toString() {
            return key + "=" + value;
        }

        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public final boolean equals(Object o) {
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?, ?> e = (Map.Entry<?, ?>) o;
                if (Objects.equals(key, e.getKey()) &&
                        Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
    }

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

    static final class TreeNode<K, V> extends Entry<K, V> {
        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);
        }

        final TreeNode<K, V> root() {    //找到根节点
            for (TreeNode<K, V> r = this, p; ; ) {
                if ((p = r.parent) == null)
                    return r;
                r = p;
            }
        }

        //这个方法是TreeNode中的方法,this为双向链表的头结点
        final void treeify(Node<K, V>[] tab) {
            TreeNode<K, V> root = null;  //红黑树的根节点
            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) {
                    x.parent = null;
                    x.red = false;  //红黑树的根节点一定是黑色的
                    root = x;
                } else {
                    K k = x.key;
                    int h = x.hash;
                    Class<?> kc = null;
                    for (TreeNode<K, V> p = root; ; ) {
                        int dir, ph;   //判断
                        K pk = p.key;
                        //根据hash值判断是左子树还是右子树
                        if ((ph = p.hash) > h)
                            dir = -1;
                        else if (ph < h)
                            dir = 1;
                        else if ((kc == null &&
                                (kc = comparableClassFor(k)) == null) ||
                                (dir = compareComparables(kc, k, pk)) == 0)
                            dir = tieBreakOrder(k, pk);

                        TreeNode<K, V> xp = p;
                        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);
        }

        /**
         *  红黑树自平衡核心方法
         *
         * @param root  根节点
         * @param x 当前节点
         * @param <K>   key泛型
         * @param <V>   value泛型
         * @return 自平衡后的根节点
         */
        static <K, V> TreeNode<K, V> balanceInsertion(TreeNode<K, V> root, TreeNode<K, V> x) {
            x.red = true;   //插入结点是红色。理由:红色在父结点(如果存在)为黑色结点时,
            //红黑树的黑色平衡没被破坏,不需要做自平衡操作。但如果插入结点是黑色,
            //那么插入位置所在的子树黑色结点总是多1,必须做自平衡。(所有插入操作都是在叶子结点进行的,叶子节点一定是黑色)
            //xp:当前节点x的父节点
            //xpp:当前节点x的爷爷节点
            //xppl:当前节点x的爷爷节点的左子节点
            //xppr:当前节点x的爷爷节点的右子节点
            for (TreeNode<K, V> xp, xpp, xppl, xppr; ; ) {
                if ((xp = x.parent) == null) {  //如果当前节点没有父节点,代表x就是根节点,根节点为黑色
                    x.red = false;
                    return x;
                } else if (!xp.red || (xpp = xp.parent) == null)
                    //情况1:父节点xp为黑色,当前节点x为红色。因此红黑树已经自平衡,直接返回就可以了
                    //情况2:父节点xp为红色,根节点xp为黑色,当前节点x为红色,已经自平衡了(满足5大特性)
                    return root;

                //此时当前节点x为红色,父节点xp为红色,祖父节点xpp一定是黑色
                if (xp == (xppl = xpp.left)) {//如果父节点是祖父节点的左子节点xppl
                    if ((xppr = xpp.right) != null && xppr.red) {   //如果存在叔叔节点(右),并且还是红色
                        xppr.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;
                    } else {    //如果不存在叔叔节点  或者叔叔节点还是黑色
                        if (x == xp.right) {
                            root = rotateLeft(root, x = xp);    //左旋父节点xp,
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        if (xp != null) {
                            xp.red = false;
                            if (xpp != null) {
                                xpp.red = true;
                                root = rotateRight(root, xpp);
                            }
                        }
                    }
                } else { //如果xp是xpp的右子节点
                    if (xppl != null && xppl.red) {
                        xppl.red = false;
                        xp.red = false;
                        xpp.red = true;
                        x = xpp;
                    } else {
                        if (x == xp.left) {
                            root = rotateRight(root, x = xp);
                            xpp = (xp = x.parent) == null ? null : xp.parent;
                        }
                        if (xp != null) {
                            xp.red = false;
                            if (xpp != null) {
                                xpp.red = true;
                                root = rotateLeft(root, xpp);
                            }
                        }
                    }
                }
            }
        }

        /**
         * @param map   当前hashmap对象
         * @param tab   底层table
         * @param index 当前红黑树在table中的索引
         * @param bit   当前table的length
         */
        final void split(HashMap源码分析<K, V> map, Node<K, V>[] tab, int index, int bit) {
            TreeNode<K, V> b = this;    //当前table中某位置处的红黑树
            // 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;
                if ((e.hash & bit) == 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 {
                    tab[index + bit] = hiHead;
                    if (loHead != null)
                        hiHead.treeify(tab);
                }
            }
        }

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

        /**
         * @param h hash(key)
         * @param k key
         * @return
         */
        final TreeNode<K, V> getTreeNode(int h, Object k) {
            return ((parent != null) ? root() : this).find(h, k, null);
        }

        final TreeNode<K, V> find(int h, Object k, Class<?> kc) {
            TreeNode<K, V> p = this;
            do {
                int ph, dir;
                K pk;
                TreeNode<K, V> pl = p.left, pr = p.right, q;
                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;
                else if (pl == null)
                    p = pr;
                else if (pr == null)
                    p = pl;
                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;
                else
                    p = pl;
            } while (p != null);
            return null;
        }

        static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root, TreeNode<K,V> p) {
            TreeNode<K,V> r, pp, rl;
            if (p != null && (r = p.right) != null) {
                if ((rl = p.right = r.left) != null)
                    rl.parent = p;
                if ((pp = r.parent = p.parent) == null)
                    (root = r).red = false;
                else if (pp.left == p)
                    pp.left = r;
                else
                    pp.right = r;
                r.left = p;
                p.parent = r;
            }
            return root;
        }

        static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root, TreeNode<K,V> p) {
            TreeNode<K,V> l, pp, lr;
            if (p != null && (l = p.left) != null) {
                if ((lr = p.left = l.right) != null)
                    lr.parent = p;
                if ((pp = l.parent = p.parent) == null)
                    (root = l).red = false;
                else if (pp.right == p)
                    pp.right = l;
                else
                    pp.left = l;
                l.right = p;
                p.parent = l;
            }
            return root;
        }

        /**
         *  找到key的位置更新或插入,还需要保证红黑树自平衡
         *
         * @param map   this
         * @param tab   底层table数组
         * @param h key的hash
         * @param k key
         * @param v value
         * @return
         */
        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;
                //判断应该是左子树还是右子树
                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);
                }

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

        static int tieBreakOrder(Object a, Object b) {
            int d;
            if (a == null || b == null ||
                    (d = a.getClass().getName().
                            compareTo(b.getClass().getName())) == 0)
                d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
                        -1 : 1);
            return d;
        }

        static <K,V> void moveRootToFront(Node<K,V>[] tab, TreeNode<K,V> root) {
            int n;
            if (root != null && tab != null && (n = tab.length) > 0) {
                int index = (n - 1) & root.hash;
                TreeNode<K,V> first = (TreeNode<K,V>)tab[index];
                if (root != first) {
                    Node<K,V> rn;
                    tab[index] = root;
                    TreeNode<K,V> rp = root.prev;
                    if ((rn = root.next) != null)
                        ((TreeNode<K,V>)rn).prev = rp;
                    if (rp != null)
                        rp.next = rn;
                    if (first != null)
                        first.prev = root;
                    root.next = first;
                    root.prev = null;
                }
                assert checkInvariants(root);
            }
        }

    }

    //计算key的hash值,用于散列分布到数组索引上
    //hash函数大概的作用就是:高16bit不变,低16bit和高16bit做了一个异或,目的是减少碰撞
    //目的:int index = (n - 1) & hash(key);较少碰撞,散列均匀
    //如果直接使用key的hashcode()作为hash很容易发生碰撞。比如,在n - 1为15(0x1111)时,散列值真正生效的只是低4位。
    //当新增的键的hashcode()是2,18,34这样恰好以16的倍数为差的等差数列,就产生了大量碰撞。
    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

    //hashmap的核心方法:新增键值对
    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

    //hashmap的核心方法:通过key获取value
    public V get(Object key) {
        Node<K, V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
    }

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
        Node<K, V>[] tab;
        Node<K, V> p;
        int n, i;
        //1.看table数组是否已经初始化
        if ((tab = table) == null || (n = tab.length) == 0) //还没有初始化table
            n = (tab = resize()).length;    //初始化table,分配内存

        //2.找到该key对应数组中的位置,(n - 1) & hash就是下标,前提:n是2的幂次方
        //在算index时,用位运算(n-1) & hash而不是模运算 hash % n的好处
        //2.1位运算消耗资源更少,更有效率
        //2.2避免了hashcode为负数的情况
        //为什么capcity是2的幂?
        //因为 算index时用的是(n-1) & hash,这样就能保证n -1是全为1的二进制数,如果不全为1的话,存在某一位为0,那么0,1与0与的结果都是0,这样便有可能将两个hash不同的值最终装入同一个桶中,造成冲突。所以必须是2的幂。
        if ((p = tab[i = (n - 1) & hash]) == null)
            //当前桶无元素,直接放就行了
            tab[i] = newNode(hash, key, value, null);
        else {
            //桶内有元素
            Node<K, V> e;
            K k;
            //key是否存在
            if (p.hash == hash &&
                    ((k = p.key) == key || (key != null && key.equals(k))))
                //桶内第一个元素的key等于待放入的key,用
                e = p;
            else if (p instanceof TreeNode) //如果节点类型是树,说明此时已经把链表转出红黑树了
                e = ((TreeNode<K, V>) p).putTreeVal(this, tab, hash, key, value);
            else {//桶内还是一个链表,则插入链尾(尾插)
                //此时还是链表结构的,没有转成红黑树,此时要做的事情有:
                //准备在链表上查找key是否已经存在,如果存在直接用新value值覆盖老value值
                //如果不存在,就需要在链表上插入节点,如果节点数超过8个,就将链表转成红黑树
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) { //访问到链表尾部了,此时key没有重复,可以在链表尾部插入新节点了
                        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))))
                        //发现链表中key重复了,直接break,重复的节点保存在e中
                        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;
    }

    final Node<K, V> getNode(int hash, Object key) {
        Node<K, V>[] tab;
        Node<K, V> first, e;
        int n;
        K k;
        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;
            if ((e = first.next) != null) {
                if (first instanceof TreeNode)  //桶已经树化
                    return ((TreeNode<K, V>) first).getTreeNode(hash, key);
                do {    //任然是链表,往下遍历就行了
                    if (e.hash == hash &&
                            ((k = e.key) == key || (key != null && key.equals(k))))
                        return e;
                } while ((e = e.next) != null);
            }
        }
        return null;
    }

    //将hash对应table下标处的单向链表转成双向链表,然后再将这一个双向链表转成红黑树
    final void treeifyBin(Node<K, V>[] tab, int hash) {
        int n, index;
        Node<K, V> e;
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) //如果table数组还没有被初始化,或者数组长度小于64
            resize();   //
        else if ((e = tab[index = (n - 1) & hash]) != null) {   //该hash对应table位置上不为空
            TreeNode<K, V> hd = null, tl = null;
            //do while循环目的:将单向链表转成双向链表
            do {
                TreeNode<K, V> p = replacementTreeNode(e, null); //将链表节点转成树节点
                if (tl == null)
                    hd = p;
                else {
                    p.prev = tl;
                    tl.next = p;
                }
                tl = p;
            } while ((e = e.next) != null);
            if ((tab[index] = hd) != null)  //将双向链表头结点地址存入该hash值对应的下标处
                hd.treeify(tab);    //着手开始将这一个双向链表转成红黑树了
        }
    }

    /**
     * resize扩容操作,主要用在两处:
     * 向一个空的HashMap中执行put操作时,会调用resize()进行初始化,要么默认初始化,capacity为16,要么根据传入的值进行初始化
     * put操作后,检查到size已经超过threshold,那么便会执行resize,进行扩容,如果此时capcity已经大于了最大值,那么便把threshold置为int最大值,否则,对capcity,threshold进行扩容操作。
     * 发生了扩容操作,那么必须Map中的所有的数进行再散列,重新装入。
     * <p>
     * 扩容后需要重新散列的原因:
     * 扩容前:某hash(key)=1000,n = 8,此时 (n-1) & hash = 0111 & 1000 = 0
     * 扩容后:                n = 16,此时(n-1) & hash = 1111 & 1000 = 1
     * 散列位置发生了变化,如果扩容后不重新散列,相同的hash(key)可能会散列到不同的索引上
     * <p>
     * 如果cap由8扩容16,
     * 8-1= 00111
     * 16-1=01111
     */
    final Node<K, V>[] resize() {
        Node<K, V>[] oldTab = table;
        int oldCap = (oldTab == null) ? 0 : oldTab.length;  //当前的桶数
        int oldThr = threshold; //当前的扩容阈值
        int newCap, newThr = 0;
        if (oldCap > 0) {
            if (oldCap >= MAXIMUM_CAPACITY) {
                threshold = Integer.MAX_VALUE;
                return oldTab;
            } else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && //2倍扩容
                    oldCap >= DEFAULT_INITIAL_CAPACITY)
                newThr = oldThr << 1; // double threshold
        } else if (oldThr > 0) {// initial capacity was placed in threshold
            newCap = oldThr;
        } else {               // zero initial threshold signifies using defaults
            newCap = DEFAULT_INITIAL_CAPACITY;
            newThr = (int) (DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        if (newThr == 0) {
            float ft = (float) newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float) MAXIMUM_CAPACITY ?
                    (int) ft : Integer.MAX_VALUE);
        }
        threshold = newThr;
        Node<K, V>[] newTab = (Node<K, V>[]) new Node[newCap];  //准备扩容数组了
        table = newTab;
        if (oldTab != null) {
            for (int j = 0; j < oldCap; ++j) {
                Node<K, V> e;
                if ((e = oldTab[j]) != null) {
                    oldTab[j] = null;   //gc
                    if (e.next == null) //当前桶上就一个节点
                        newTab[e.hash & (newCap - 1)] = e;
                    else if (e instanceof TreeNode) //当前桶已经树化
                        ((TreeNode<K, V>) e).split(this, newTab, j, oldCap);
                    else { //当前桶还是链表
                        Node<K, V> loHead = null, loTail = null;
                        Node<K, V> hiHead = null, hiTail = null;
                        Node<K, V> next;
                        do {
                            next = e.next;
                            //扩容前计算索引位置index = (n - 1) & hash,此时n = oldCap
                            // int oldIndex = (oldCap - 1) & hash;
                            //扩容后
                            //int newIndex = (2 * oldCap - 1) & hash;
                            //eg1:如果扩容前n = 4,扩容后就是n = 8
                            // 0011 & hash      0111 & hash  扩容前后索引位置是否发生变化取决于hash的第低三位是否是0还是1
                            //eg2:如果扩容前n = 8,扩容后就是n = 16
                            // 0111 & hash     1111 & hash 取决于第低四位是否是0还是1
                            //如果是0,0按位与任何数都是0,此时扩容后位置没有发生变化
                            //如果是1,此时扩容后位置会发生变化:此时位置如何变化呢?
                            //索引位置在高位多了一个1,就是增加了oldCap
                            //oldCap可能是 0010,0100,1000,...
                            if ((e.hash & oldCap) == 0) {   //该位置处扩容后位置不会变化
                                if (loTail == null)
                                    loHead = e;
                                else
                                    loTail.next = e;
                                loTail = e;
                            } else {    //该位置处扩容后位置发生改变
                                if (hiTail == null)
                                    hiHead = e;
                                else
                                    hiTail.next = e;
                                hiTail = e;
                            }
                        } while ((e = next) != null);
                        if (loTail != null) {
                            loTail.next = null;
                            newTab[j] = loHead; //2倍扩容后索引位置不变
                        }
                        if (hiTail != null) {
                            hiTail.next = null;
                            newTab[j + oldCap] = hiHead;//2倍扩容后索引位置增加oldCap
                        }
                    }
                }
            }
        }
        return newTab;
    }

    /*计算大于等于cap的最小2次幂的数
    //原理:只需要关注二进制中第一个高位为1的位即可,其余为可以忽略
    *1.假设在第n位(......n n-1n-2 ......2 1)
    *2.无符号右移1位再按位或运算,则n n-1都是1           -->有2位为1
    *3.无符号右移2位再按位或运算,则n ......n-3都是1   -->有4位为1
    *4.无符号右移4位再按位或运算,则n ......n-7都是1   -->有8位为1
    *5.无符号右移8位再按位或运算,则n ......n-15都是1   -->有16位为1
    *6.无符号右移16位再按位或运算,则n ......n-31都是1   -->有32位为1
    *7.java int类型4字节,32位,正数符号位为0,且无符号右移时最多31位为1,即最大生成Interger.MAX_VALUE=0x7FFFFFFF
    */
    static final int tableSizeFor(int cap) {
        int n = cap - 1;//如果cap已经是2的幂,又没有执行这个减1操作,则执行完后面的几条无符号右移操作之后,返回的capacity将是这个cap的2倍
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

    Node<K, V> replacementNode(Node<K, V> p, Node<K, V> next) {
        return new Node<>(p.hash, p.key, p.value, next);
    }

    Node<K, V> newNode(int hash, K key, V value, Node<K, V> next) {
        return new Node<>(hash, key, value, next);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值