Arraylist、LinkedList,hashmap扩容源码解读

ArrayList

arrayList的add源码流程解析

在这里插入图片描述

第一步进入add方法
public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("1");//这里入口
    }
第二步查看一下构造函数
// 初始化ArrayList实例,则elementData={}
    public ArrayList() {
   		 // Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; 
    }
第三步到达add方法

步骤:

  1. ensureCapacityInternal 方法来判断是否需要扩容
  2. 把传入的值写入elementData[size]
  3. size++;
 public boolean add(E e) {
        /** 确定是否需要扩容,如果需要,则进行扩容操作*/
        ensureCapacityInternal(size + 1);  // size初始值是为0的
        // eg1:size=0,elementData[0]="1",然后size自增为1
        elementData[size++] = e;
        return true;
    }
第四步到达ensureCapacityInternal方法
  1. calculateCapacity方法是计算ArrayList的容量
  2. ensureExplicitCapacity方法确保,明确的ArrayList的容量
private void ensureCapacityInternal(int minCapacity) {//minCapacity(最小容量)等于已存在元素加1
		//calculateCapacity方法是计算ArrayList的容量
		//ensureExplicitCapacity方法确保,明确的ArrayList的容量
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
第五步到达calculateCapacity方法
/**
     * 计算ArrayList的容量
     *
     * 如果elementData数组中没有已存储的元素,则返回默认值10
     * 否则,返回minCapacity。
     *
     * @param elementData 底层存储ArrayList元素的数组
     * @param minCapacity ArrayList中的元素个数(最小容量)
     * @return
     */
private static int calculateCapacity(Object[] elementData, int minCapacity) {
		
        //判断elementData(底层存储ArrayList元素的数组)是否等于空数组
        //private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            // ArrayList默认的容量为10个Object元素
            // private static final int DEFAULT_CAPACITY = 10;
            //和默认容量做最大值比较,如果小于默认容量就返回默认容量,否则返回minCapacity
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
第六部步先回到ensureCapacityInternal方法在进入ensureExplicitCapacity方法

modCount:默认初始值为0

  1. 这个成员变量记录着集合的修改次数,也就每次add或者remove它的值都会加1
  2. ArrayList是非线程安全的,在使用迭代器遍历的时候,用来检查列表中的元素是否发生结构性变化(列表元素数量发生改变)了,主要在多线程环境下需要使用,防止一个线程正在迭代遍历,另一个线程修改了这个列表的结构。就会抛出异常:ConcurrentModificationException。
/**
     * 确保明确的ArrayList的容量
     *
     * @param minCapacity ArrayList所需的最小容量
     */
    private void ensureExplicitCapacity(int minCapacity) {
        //这里关注一下
        modCount++;

        /** 如果所需的最小容量大于elementData数组的容量,则进行扩容操作 */
        if (minCapacity - elementData.length > 0) { 
            //扩容的方法,重点
            grow(minCapacity);
        }
    }
第七步进入grow方法
    /**
     * 扩容操作
     * @param minCapacity 所需要的最小扩容量
     */
    // eg1:第一次新增元素,minCapacity=10,即:需要将elementData的0长度扩容为10长度。
    private void grow(int minCapacity) {

        /** 原有数组elementData的长度*/
        int oldCapacity = elementData.length;

        /**
         * A >> 1 等于 A/2
         * 举例: 3 >> 1 = 3/2 = 1
         *     4 >> 1 = 4/2 = 2
         * ------------------------
         * A << 1 等于 A*2
         * 举例: 3 << 1 = 3*2 = 6
         *     4 << 1 = 4*2 = 8
         *
         * 000100 >> 1 = 000010
         * 000100 << 1 = 001000
         */
        /** 新增oldCapacity的一半整数长度作为newCapacity的额外增长长度 */
        int newCapacity = oldCapacity + (oldCapacity >> 1); // eg1:newCapacity=0+(0>>1)=0

        /** 新的长度newCapacity依然无法满足需要的最小扩容量minCapacity,则新的扩容长度为minCapacity */
        if (newCapacity - minCapacity < 0) {
            // eg1:newCapacity=10
            newCapacity = minCapacity;
        }

        /** 新的扩容长度newCapacity超出了最大的数组长度MAX_ARRAY_SIZE */
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            newCapacity = hugeCapacity(minCapacity);
        }

        /** 扩展数组长度为newCapacity,并且将旧数组中的元素赋值到新的数组中 */
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    /**
     * 要分配的数组的最大大小。一些vm在数组中保留一些头字。
     * 尝试分配较大的数组可能会导致OutOfMemory错误:请求的数组大小超过了虚拟机限制
     *  MAX_ARRAY_SIZE    = 2147483639 = 01111111 11111111 11111111 11110111
     *  Integer.MAX_VALUE = 2147483647 = 01111111 11111111 11111111 11111111
     *  public static final int   MAX_VALUE = 0x7fffffff;
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    
     private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) { // overflow
            throw new OutOfMemoryError();
        }
        return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
    }

arrayList的remove源码解析

 public E remove(int index) {
        /** 校验传入的参数index是否超出了数组的最大下标,如果超出,则抛出:IndexOutOfBoundsException异常*/
        rangeCheck(index);

        /** 集合的修改次数加1 */
        modCount++;

        // eg1:String oldValue="a1"
        /** 获得index下标对应的旧值oldValue */
        E oldValue = elementData(index);

        // eg1:numMoved=4-0-1=3
        /** 获得需要移动元素的个数 */
        int numMoved = size - index - 1;
        if (numMoved > 0) {
            /**
             * {"a1","a2","a3","a4"}
             *
             * 假设删除"a2",那么index=1, numMoved=2, 那么下面的语句执行的就是:
             * 将第一个入参的elementData从第2位"a3"(index+1)开始复制2位(numMoved)即:"a3","a4";
             * 复制到第三个入参elementData的第1位(index),即elementData变成 {"a1","a3","a4","a4"}
             */
            System.arraycopy(elementData, index + 1, elementData, index, numMoved);
        }
        /** 通知jvm将之前的最后一位元素进行垃圾回收 */
        elementData[--size] = null; // clear to let GC do its work

        /** 返回已被删除的元素 */
        return oldValue;
    }

LinkedList

LinkedList add流程图

在这里插入图片描述

源码解读第一步进入add方法

	/**
	 * 新增元素
	 */
	public boolean add(E e) {
        linkLast(e);
        return true;
    }

第二步进入linkLast方法

 	/**
     * 将新添加的元素e作为链表的最后一个元素, 并维护进去
     */
    void linkLast(E e) {
        final Node<E> l = last;

        //  newNode    null<--"a1"-->null
        /** 创建一个e的Node节点,前置指向原last节点,后置指向null */
        final Node<E> newNode = new Node<>(l, e, null);

        /** 将newNode节点赋值为last节点 */
        last = newNode;

        // eg1: l=null
        if (l == null) {
            /** 如果是第一个添加的元素,则first指针指向该结点*/
            first = newNode; // eg1: first指向newNode
        } else {
            /** 如果不是第一个添加进来的元素,则更新l的后置结点指向新添加的元素结点newNode*/
            l.next = newNode;
        }
        size++;
        modCount++;
    }

HashMap

第一步进入Put方法

public V put(K key, V value) {
		//putVal是添加元素的方法
        //hash是哈希扰动函数
        return putVal(hash(key), key, value, false, true);
    }

第二步进入hash哈希扰动函数

在这里插入图片描述

static final int hash(Object key) {
        int h;
        /**
         * 按位异或运算(^):两个数转为二进制,然后从高位开始比较,如果相同则为0,不相同则为1。
         *
         * 扰动函数————(h = key.hashCode()) ^ (h >>> 16) 表示:
         *      将key的哈希code一分为二。其中:
         *      【高半区16位】数据不变。
         *      【低半区16位】数据与高半区16位数据进行异或操作,以此来加大低位的随机性。
         * 注意:如果key的哈希code小于等于16位,那么是没有任何影响的。只有大于16位,才会触发扰动函数的执行效果。
         * */
        // egx: 110100100110^000000000000=110100100110,由于k1的hashCode都是在低16位,所以原样返回3366
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

        /**
         * case1:
         *  h=高16位(全是0) and 低16位(有1)
         *  h >>> 16 = 低16位全部消失,那么变成了32位(全是0)
         *  h ^ (h >>> 16) = 原样输出
         * case2:
         *  h=高16位(有1) and 低16位(有1)
         *  h >>> 16 = 低16位全部消失,那么变成了高16位(全是0)and低16位(有1)
         *  h ^ (h >>> 16) = 不是原样输出  将原高16位于原低16位进行扰动。
         */
    }

第三步进入putVal函数当中

/**
     * Implements Map.put and related methods.
     *
     * @param hash         key的哈希值
     * @param key          key值
     * @param value        value值
     * @param onlyIfAbsent 如果是true,则不改变已存在的value值
     * @param evict        驱逐,赶出,逐出 if false, the table is in creation mode.
     *
     * @return previous value, or null if none
     */

final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
Node<K, V>[] tab;
Node<K, V> p;
int n, i;

    // eg1: table=null
    // eg2: table是长度为16的Node数组,且table[1]=Node(1, 1, "a1", null)
    // eg3: table是长度为16的Node数组,且table[1]=Node(1, 1, "a1", null) ... table[6]=Node(6, 6, "a6", null)
    // eg4: table是长度为16的Node数组,且table[1]=Node(1, 1, "a1", null) ... table[6]=Node(6, 6, "a6", null)
    // eg6: table是长度为16的Node数组,且table[1]=Node(1, 1, "a1", null) ... table[6]=Node(6, 6, "a6", null)
    /** 如果是空的table,那么默认初始化一个长度为16的Node数组*/
    if ((tab = table) == null || (n = tab.length) == 0) {
        // eg1: resize返回(Node<K, V>[]) new Node[16],所以:tab=(Node<K, V>[]) new Node[16], n=16
        n = (tab = resize()).length;
    }

    // eg1: i = (n-1)&hash = (16-1)&0 = 1111&0000 = 0000 = 0; 即:p=tab[0]=null
    // eg2: i = (n-1)&hash = (16-1)&1 = 1111&0001 = 0001 = 1; 即:p=tab[1]=null
    // eg3: i = (n-1)&hash = (16-1)&16 = 1111&10000 = 0000 = 0; 即:p=tab[0]=Node(0, 0, "a0", null)
    // eg4: i = (n-1)&hash = (16-1)&32 = 1111&100000 = 0000 = 0; 即:p=tab[0]=Node(0, 0, "a0", null)
    // eg6: i = (n-1)&hash = (16-1)&128 = 1111&10000000 = 0000 = 0; 即:p=tab[0]=Node(0, 0, "a0", null)
    /** 如果计算后的下标i,在tab数组中没有数据,那么则新增Node节点*/
    if ((p = tab[i = (n - 1) & hash]) == null) {
        // eg1: tab[0] = newNode(0, 0, "a0", null)
        // eg2: tab[1] = newNode(1, 1, "a1", null)
        tab[i] = newNode(hash, key, value, null);
    } else { /** 如果计算后的下标i,在tab数组中已存在数据,则执行以下逻辑 */
        Node<K, V> e;
        K k;
        // eg3: p.hash==0, hash==16,所以返回false
        // eg4: p.hash==0, hash==32,所以返回false
        // eg6: p.hash==0, hash==128,所以返回false
        if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) { /** 如果与已存在的Node是相同的key值*/
            e = p;
        }
        // eg3: p instanceof Node,所以为false
        // eg4: p instanceof Node,所以为false
        // eg6: p instanceof Node,所以为false
        else if (p instanceof TreeNode) { /** 如果与已存在的Node是相同的key值,并且是树节点*/
            e = ((TreeNode<K, V>) p).putTreeVal(this, tab, hash, key, value);
        } else { /** 如果与已存在的Node是相同的key值,并且是普通节点,则循环遍历链式Node,并对比hash和key,如果都不相同,则将新的Node拼装到链表的末尾。如果相同,则进行更新。*/
            for (int binCount = 0; ; ++binCount) {
                // eg3: p.next == null
                // eg4-loop1: p.next == Node(16, 16, "a16", null) 不为空
                // eg4-loop2: p.next == null
                /** 获得p节点的后置节点,赋值给e。直到遍历到横向链表的最后一个节点,即:该节点的next后置指针为null */
                if ((e = p.next) == null) {
                    // eg3: p.next = newNode(16, 16, "a16", null);
                    // eg4-loop2: p.next == newNode(32, 32, "a32", null);
                    // eg6: p.next == newNode(128, 128, "a128", null);
                    p.next = newNode(hash, key, value, null);

                    // eg3: binCount == 0
                    // eg4-loop2: binCount == 1
                    /** binCount从0开始,如果Node链表大于8个Node,那么试图变为红黑树 */
                    if (binCount >= TREEIFY_THRESHOLD - 1) {
                        // eg6: tab={newNode(0, 0, "a0", [指向后面1个链表中的7个node]), newNode(1, 1, "a1", null)}, hash=128
                        treeifyBin(tab, hash);
                    }
                    // eg3: break
                    // eg4-loop2: break
                    break;
                }
                // eg4-loop1: e.hash==16 hash==32 所以返回false
                /** 针对链表中的每个节点,都来判断一下,是否待插入的key与已存在的链表节点相同,如果相同,则跳出循环,并在后续的操作中,将该节点内容更新为最新的插入值 */
                if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) {
                    break;
                }
                // eg4-loop1: p=e=Node(16, 16, "a16", null)
                p = e;
            }
        }

        // eg3: e = null
        // eg4: e = null
        /** 如果存在相同的key值*/
        if (e != null) {
            // egx: String oldValue = "v1"
            V oldValue = e.value;
            // egx: onlyIfAbsent=false
            if (!onlyIfAbsent || oldValue == null) {
                // egx: e = Node(3366, "k1", "v2", null)
                /** 则将新的value值进行更新*/
                e.value = value;
            }
            afterNodeAccess(e);
            // egx: 返回oldValue="v1"
            return oldValue;
        }
    }

    // eg1: modCount==0 ++modCount==1
    // eg2: modCount==1 ++modCount==2
    // eg3: modCount==7 ++modCount==8
    // eg4: modCount==8 ++modCount==9
    ++modCount;

    // eg1: size=0, threshold=12
    // eg2: size=1, threshold=12
    // eg3: size=7, threshold=12
    // eg4: size=8, threshold=12
    if (++size > threshold) {
        resize();
    }
    afterNodeInsertion(evict); /** doing nothing */
    return null;
}

第四步进入resize扩容方法很重要

在这里插入图片描述
在这里插入图片描述

final Node<K, V>[] resize() {
        // eg1: table=null
        // eg6: table != null
        Node<K, V>[] oldTab = table;
        // eg1: oldCap=0
        // eg6: oldCap=16
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
        // eg1: oldThr=threshold=0
        // eg6: oldThr=threshold=12
        int oldThr = threshold;
        int newCap = 0;
        int newThr = 0;
        /** 第一步:根据情况,调整新表的容量newCap和阈值newThr*/
        if (oldCap > 0) {
            /** 如果老table的长度大于等于2^30(1 << 30)        1后面有30个0*/
            if (oldCap >= MAXIMUM_CAPACITY) {
                threshold = Integer.MAX_VALUE; /** 2^31-1  1后面有30个1 */
                return oldTab;
            }
            /** 如果将老Table的长度增长2倍作为新的容量长度(newCap),是否小于2^30(1 << 30) 并且 老Table长度是否大于等于16(1 << 4)*/
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY) {
                // eg6: newCap=32, newThr=24
                newThr = oldThr << 1;
            }
        } else if (oldThr > 0) {
            newCap = oldThr;
        } else {
            // eg1: oldCap=0 newCap=16 newThr=0.75f*16=12
            newCap = DEFAULT_INITIAL_CAPACITY; /** 默认【表容量】为16(1 << 4) */
            newThr = (int) (DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); /** 默认【阈值因子】为0.75f */
        }

        if (newThr == 0) {
            float ft = (float) newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float) MAXIMUM_CAPACITY ? (int) ft : Integer.MAX_VALUE);
        }
        // eg1: threshold=newThr=12
        // eg6: threshold=newThr=24
        threshold = newThr;

        /** 第二步:根据newCap和newThr,构建新数组 */
        /** 初始化新表*/
        @SuppressWarnings({"rawtypes", "unchecked"})
        Node<K, V>[] newTab = (Node<K, V>[]) new Node[newCap];
        // eg1: table=newTab=(Node<K, V>[]) new Node[16];
        // eg6: table=newTab=(Node<K, V>[]) new Node[32];
        table = newTab;
        // eg1: oldTab=null
        if (oldTab != null) { /** 如果老的table里有数据,则进行数据迁移*/
            // eg6: oldCap=16
            /** 循环纵向数组中的每个槽位Cap */
            for (int j = 0; j < oldCap; ++j) {
                Node<K, V> e;
                // eg6-loop1: j=0, e=oldTab[0]=Node(0, 0, "a0", nodeRef)
                // eg6-loop2: j=1, e=oldTab[1]=Node(1, 1, "a1", null)
                if ((e = oldTab[j]) != null) {
                    // eg6-loop1: oldTab[0] = null
                    // eg6-loop2: oldTab[1] = null
                    oldTab[j] = null;
                    // eg6-loop1: e.next=Node(16, 16, "a16", nodeRef)
                    // eg6-loop2: e.next==null
                    if (e.next == null) { /** 没有后置节点,说明e是最后一个节点*/
                        // eg6-loop2: e.hash==1, newCap=32, 1&(32-1)==1 即:newTab[1]=Node(1, 1, "a1", null)
                        newTab[e.hash & (newCap - 1)] = e;
                    } else if (e instanceof TreeNode) { /** e是树节点*/
                        ((TreeNode<K, V>) e).split(this, newTab, j, oldCap);
                    } else {
                        Node<K, V> loHead = null;
                        Node<K, V> loTail = null;
                        Node<K, V> hiHead = null;
                        Node<K, V> hiTail = null;
                        Node<K, V> next;
                        do {
                            // eg6-loop1-loop1: next=e.next=Node(16, 16, "a16", nodeRef)
                            // eg6-loop1-loop2: next=e.next=Node(32, 32, "a32", nodeRef)
                            // eg6-loop1-loop3: next=e.next=Node(48, 48, "a48", nodeRef)
                            // eg6-loop1-loop4: next=e.next=Node(64, 64, "a64", nodeRef)
                            // eg6-loop1-loop5: next=e.next=Node(80, 80, "a80", nodeRef)
                            // eg6-loop1-loop6: next=e.next=Node(96, 96, "a96", nodeRef)
                            // eg6-loop1-loop7: next=e.next=Node(112, 112, "a112", nodeRef)
                            // eg6-loop1-loop8: next=e.next=Node(128, 128, "a128", nodeRef)
                            // eg6-loop1-loop9: next=e.next=null
                            next = e.next; /** 获得oldTab数组下标的Node列表的下一个节点*/
                            // eg6-loop1-loop1: e.hash=0, oldCap=16,  00000000&10000==00000==0
                            // eg6-loop1-loop2: e.hash=16, oldCap=16, 00010000&10000==10000==16
                            // eg6-loop1-loop3: e.hash=32, oldCap=16, 00100000&10000==00000==0
                            // eg6-loop1-loop4: e.hash=48, oldCap=16, 00110000&10000==10000==16
                            // eg6-loop1-loop5: e.hash=64, oldCap=16, 01000000&10000==00000==0
                            // eg6-loop1-loop6: e.hash=80, oldCap=16, 01010000&10000==00000==16
                            // eg6-loop1-loop7: e.hash=96, oldCap=16, 01100000&10000==00000==0
                            // eg6-loop1-loop8: e.hash=112, oldCap=16, 01110000&10000==10000==16
                            // eg6-loop1-loop9: e.hash=128, oldCap=16, 10000000&10000==10000==0
                            if ((e.hash & oldCap) == 0) { /** 计算e在老表oldTab的下标,如果是第一个Node,即:下标index==0*/
                                if (loTail == null) {
                                    // eg6-loop1-loop1: loHead=e=Node(0, 0, "a0", nodeRef)
                                    loHead = e; /** 将loHead指向oldTab数组第一个下标的第一个元素e*/
                                } else {
                                    // eg6-loop1-loop3: loTail.next=e=Node(32, 32, "a32", nodeRef)
                                    // eg6-loop1-loop5: loTail.next=e=Node(64, 64, "a64", nodeRef)
                                    // eg6-loop1-loop7: loTail.next=e=Node(96, 96, "a96", nodeRef)
                                    // eg6-loop1-loop9: loTail.next=e=Node(128, 128, "a128", nodeRef)
                                    loTail.next = e; /** 建立新的链表 */
                                }
                                // eg6-loop1-loop1: loTail=e=Node(0, 0, "a0", nodeRef)
                                // eg6-loop1-loop3: loTail=e=Node(32, 32, "a32", nodeRef)
                                // eg6-loop1-loop5: loTail=e=Node(64, 64, "a64", nodeRef)
                                // eg6-loop1-loop7: loTail=e=Node(96, 96, "a96", nodeRef)
                                // eg6-loop1-loop9: loTail=e=Node(128, 128, "a128", nodeRef)
                                loTail = e; /** 将loTail指向oldTab数组第一个下标的最后一个元素e*/
                            } else { /** 如果不是oldTab中的第一个下标Node*/
                                if (hiTail == null) {
                                    // eg6-loop1-loop2: hiHead=e=Node(16, 16, "a16", nodeRef)
                                    hiHead = e;
                                } else {
                                    // eg6-loop1-loop4: hiTail.next=e=Node(48, 48, "a48", nodeRef)
                                    // eg6-loop1-loop6: hiTail.next=e=Node(80, 80, "a80", nodeRef)
                                    // eg6-loop1-loop8: hiTail.next=e=Node(112, 112, "a112", nodeRef)
                                    hiTail.next = e; /** 建立新的链表 */
                                }
                                // eg6-loop1-loop2: hiTail=e=Node(16, 16, "a16", nodeRef)
                                // eg6-loop1-loop4: hiTail=e=Node(48, 48, "a48", nodeRef)
                                // eg6-loop1-loop6: hiTail=e=Node(80, 80, "a80", nodeRef)
                                // eg6-loop1-loop8: hiTail=e=Node(112, 112, "a112", nodeRef)
                                hiTail = e;
                            }
                        }
                        // eg6-loop1-loop1: e=next=Node(16, 16, "a16", nodeRef)
                        // eg6-loop1-loop2: e=next=Node(32, 32, "a32", nodeRef)
                        // eg6-loop1-loop3: e=next=Node(48, 48, "a48", nodeRef)
                        // eg6-loop1-loop4: e=next=Node(64, 64, "a64", nodeRef)
                        // eg6-loop1-loop5: e=next=Node(80, 80, "a80", nodeRef)
                        // eg6-loop1-loop6: e=next=Node(96, 96, "a96", nodeRef)
                        // eg6-loop1-loop7: e=next=Node(112, 112, "a112", nodeRef)
                        // eg6-loop1-loop8: e=next=Node(128, 128, "a128", nodeRef)
                        // eg6-loop1-loop9: e=next=null
                        while ((e = next) != null); /** do-while */

                        // eg6-loop1: loTail=Node(128, 128, "a128", null)
                        if (loTail != null) {
                            loTail.next = null;
                            // eg6-loop1: j=0, newTab[0]=loHead=Node(0, 0, "a0", nodeRef)
                            newTab[j] = loHead;
                        }

                        // eg6-loop1: loTail=Node(112, 112, "a112", nodeRef)
                        if (hiTail != null) {
                            // eg6-loop1: loTail=Node(112, 112, "a112", null)
                            hiTail.next = null;
                            // eg6-loop1: j=0, oldCap=16, newTab[16]=hiHead=Node(16, 16, "a16", nodeRef)
                            newTab[j + oldCap] = hiHead;
                        }
                    }
                }
            }
        }
        // eg1: newTab = (Node<K, V>[]) new Node[16]
        // eg6: newTab = (Node<K, V>[]) new Node[32]
        return newTab;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值