ArrayList、LinkedList和HashMap源码梳理

ArrayList

在这里插入图片描述

add(E e):新增元素

1、先判断是否需要扩容,如果需要就进行扩容,然后将元素存在size的位置,如果ArrayList为空的时候,进来的第一个元素,那么就应该将该元素放在ArrayList的第0个位置,这个时候即elementData[0] = e;然后size大小再进行++操作,表示这个时候ArrayList的大小增加了1

public boolean add(E e) {
   /** 确定是否需要扩容,如果需要,则进行扩容操作*/
   ensureCapacityInternal(size + 1);  // Increments modCount!!
   // eg1:size=0,elementData[0]="a1",然后a自增为1
   elementData[size++] = e;
   return true;
}

2、传入容器元素个数+1的值给ensureCapacityInternal方法,该方法中进行了ArrayList大小计算。该最小容量指的是ArrayList中现在的元素个数,再+1,因为我们要做的是保存操作,保存之后ArrayList大小就会+1,这样的话我们就需要保证ArrayList是否可以满足本次添加

// eg1:第一次新增元素,所以size=0,则:minCapacity=size+1=1
private void ensureCapacityInternal(int minCapacity) {
    // eg1:第一次新增元素,calculateCapacity方法返回值为DEFAULT_CAPACITY=10
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

在此方法中,我们进行重新计算ArrayList所需要的的容量大小,如果ArrayList中没有数据,那么ArrayList的大小就为10,如果不为空,那就返回ArrayList中元素的个数

/**
* 计算ArrayList的容量
 *
 * 如果elementData数组中没有已存储的元素,则返回默认值10
 * 否则,返回minCapacity。
 *
 * @param elementData 底层存储ArrayList元素的数组
 * @param minCapacity ArrayList中的元素个数
 * @return
 */
// eg1:第一次新增元素,elementData={} minCapacity=1
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        // eg1:满足if判断,DEFAULT_CAPACITY=10
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}

当第一次增加元素的时候,传进来的这个minCapacity大小为默认值10,因为我刚开始什么数据都没有的时候,我所需要的容量是10,那我所需要的容量大于我现在容器的大小,我就要进行一次扩容操作。
modCount成员变量记录着集合的修改次数,也就是每次add或者remove它的值都会加1
ArrayList是非线程安全的,在使用迭代器遍历的时候,用来检查列表中的元素是否发生结构性变化(列边元素数量发生改变了),主要是在多线程环境下使用,防止一个线程正在迭代遍历,另一个线程修改了这个列表的结构。即,在多线程对一个ArrayList的数据操作的时候,它会去判断遍历次数与modcount是否相等,如果不等就会抛出异常CurrentModificationException

/**
* 确保明确的ArrayList的容量
* @param minCapacity ArrayList所需的最小容量
*/
// eg1:第一次新增元素,minCapacity=10
private void ensureExplicitCapacity(int minCapacity) {
   // eg1: modCount++后,modCount=1
   modCount++;

   /** 如果所需的最小容量大于elementData数组的容量,则进行扩容操作 */
   if (minCapacity - elementData.length > 0) { // eg1:10-0=10,满足扩容需求
       // eg1:minCapacity=10
       grow(minCapacity);
   }
}

扩容操作,传进来的参数是所需要的最小容量,如果是第一次新增元素,那长度就要扩容为10。
记录oldCapacity,newCapacity为oldCapacity的1.5倍
如果新的长度newCapacity依然无法满足需要的最小扩容量minCapacity,则新的扩容长度值为minCapacity,因为我们扩容最终的目的是要≥minCapacity,那当我们的原newCapacity小于minCapacity的时候,那我们就需要将newCapacity设置为minCapacity即10。
如果newCapacity超出了最大的数组长度MAX_ARRAY_SIZE

Integer.MAX_VALUE - 8的原因:在数组的对象头里有一个_length字段,记录数组长度,只需要去读_length字段就可以了,所以ArrayList中定义的最大长度为Integer最大值减8,这个8就是就是存了数组_length字段。

/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*
* 要分配的数组的最大大小。一些vm在数组中保留一些头字。
* 尝试分配较大的数组可能会导致OutOfMemory错误:请求的数组大小超过了虚拟机限制
*/
// MAX_ARRAY_SIZE=2147483639=01111111 11111111 11111111 11110111
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

那么调用方法hugeCapacity,将minCapacity作为参数,此时的minCapacity为传进来的10 ,如果小于0(有符号整数,最高位1表示负数),就抛出OutOfMemoryError,否则判断minCapacity与MAX_ARRAY_SIZE的关系,如果minCapacity大,那么取Integer的最大值,如果MAX_ARRAY_SIZE大,则取MAX_ARRAY_SIZE赋值给newCapacity

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) { // overflow
        throw new OutOfMemoryError();
    }
    return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}

最后,扩展数组长度为newCapacity,并且将旧数组中的元素赋值到新的数组中

/**
 * Increases the capacity to ensure that it can hold at least the
 * number of elements specified by the minimum capacity argument.
 *
 * 扩容操作
 *
 * @param minCapacity 所需要的最小扩容量
 */
// eg1:第一次新增元素,minCapacity=10,即:需要将elementData的0长度扩容为10长度。
private void grow(int minCapacity) {

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

    /**
     * A >> 1 等于 A/2
     * eg: 3 >> 1 = 3/2 = 1
     *     4 >> 1 = 4/2 = 2
     * ------------------------
     * A << 1 等于 A*2
     * eg: 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,并且将旧数组中的元素赋值到新的数组中 */
    // eg1:newCapacity=10, 扩容elementData的length=10
    elementData = Arrays.copyOf(elementData, newCapacity);
}

get(int index):获取元素

两个步骤:一检查索引范围、二返回对应位置上的元素

/**
* Returns the element at the specified position in this list.
* 返回list中指定位置的元素
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
    rangeCheck(index);
    return elementData(index);
}

如果index大于等于list大小(因为数组的index下标都是从0开始的,所以是包含等于list),抛出IndexOutOfBoundsException

/**
 * Checks if the given index is in range.  If not, throws an appropriate
 * runtime exception.  This method does *not* check if the index is
 * negative: It is always used immediately prior to an array access,
 * which throws an ArrayIndexOutOfBoundsException if index is negative.
 */
// eg1:index=0
private void rangeCheck(int index) {
    if (index >= size) {
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
}

返回指定位置上的元素,并将元素强转为泛型中指定的类型

E elementData(int index) {
    return (E) elementData[index];
}

set(int index, E element):设置元素

三步操作:
一、判断index是否在范围内,与get方法中的范围检查方法一致
二、获得index下标对应的旧值、用于方法返回
三、将index下标对应的值,赋值为新值——element

 /**
 * Replaces the element at the specified position in this list with
 * the specified element.
 * 
 * @param index   index of the element to replace
 * @param element element to be stored at the specified position
 * @return the element previously at the specified position
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E set(int index, E element) {
    /** 判断index是否超出了ArrayList中包含的元素数量,如果超出,则抛出IndexOutOfBoundsException异常 */
    rangeCheck(index);

    /** 获得index下标对应的旧值 */
    E oldValue = elementData(index);

    /** 将index下标对应的值,赋值为新值——element */
    elementData[index] = element;

    /** 返回index下标对应的旧值 */
    return oldValue;
}

remove(int index):删除元素

1.范围校验
2.modCount++:modCount成员变量记录着集合的修改次数,也就是每次add或者remove它的值都会加1(modCount用于控制用户在并发的情况修改arraylist里的数据造成数据混乱的变量,每循环一次,就会对这个变量加1)
ArrayList是非线程安全的,在使用迭代器遍历的时候,用来检查列表中的元素是否发生结构性变化(列边元素数量发生改变了),主要是在多线程环境下使用,防止一个线程正在迭代遍历,另一个线程修改了这个列表的结构。即,在多线程对一个ArrayList的数据操作的时候,它会去判断遍历次数与modcount是否相等,如果不等就会抛出异常CurrentModificationException
3.将移除的位置后面的元素整体向前移动一位
4.通知jvm将之前的最后一位元素进行垃圾回收
5.返回已被删除的元素

// eg1:elementData中保存了{"a1","a2","a3","a4"},删除第一个元素,即:index=0
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) {
        /** 从需要删除的index后一位开始到末尾的这部分数据,整体都向前移动一个元素。*/
        System.arraycopy(elementData, index + 1, elementData, index, numMoved);
    }
    /** 通知jvm将之前的最后一位元素进行垃圾回收 */
    elementData[--size] = null; // clear to let GC do its work

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

LinkedList

在这里插入图片描述

add(E e):新增元素

 /**
 * Appends the specified element to the end of this list.
 *
 * <p>This method is equivalent to {@link #addLast}.
 *
 * @param e element to be appended to this list
 * @return {@code true} (as specified by {@link Collection#add})
 */
// eg1: e="a1"
public boolean add(E e) {
    linkLast(e);
    return true;
}
/**
 * 将新添加的元素e作为链表的最后一个元素, 并维护进去
 */
// eg1: e="a1"
void linkLast(E e) {
    final Node<E> l = last;

    // eg1: 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++;
}

get(int index):获取元素

两步
一、检查元素索引是否越界
二、返回对应结点的元素值

/**
 * Returns the element at the specified position in this list.
 *
 * @param index index of the element to return
 * @return the element at the specified position in this list
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
/**
 * 查询指定下标index的结点
 */
public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}

一、索引范围必须是在0-size之间,不包含size。不在此范围之中,抛出越界异常

/**
 * 校验是否越界
 *
 * @param index
 */
private void checkElementIndex(int index) {
    /** index >= 0 && index < size */
    if (!isElementIndex(index)) {
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
}

/**
 * Tells if the argument is the index of an existing element.
 */
private boolean isElementIndex(int index) {
    return index >= 0 && index < size;
}

二、返回结点的值
如果需要获取的index小于总长度size的一半,则从头部开始向后遍历查找
否则从尾部开始向前遍历查找

/**
 * Returns the (non-null) Node at the specified element index.
 *
 * 根据传入的index值,返回对应的结点node
 */
// eg1:index=0
Node<E> node(int index) {
    // assert isElementIndex(index);

    /** 如果需要获取的index小于总长度size的一半,则从头部开始向后遍历查找 */
    if (index < (size >> 1)) {
        Node<E> x = first;
        for (int i = 0; i < index; i++) {
            x = x.next; // 从first结点向后next查找,直到index下标node,返回node
        }
        return x;
    } else { /** 从尾部开始向前遍历查找 */
        Node<E> x = last;
        for (int i = size - 1; i > index; i--) {
            x = x.prev; // 从last结点向前prev查找,直到index下标node,返回node
        }
        return x;
    }
}

HashMap

put(K key, V value)

/**
 * Associates the specified value with the specified key in this map.
 * If the map previously contained a mapping for the key, the old
 * value is replaced.
 *
 * @param key   key with which the specified value is to be associated
 * @param value value to be associated with the specified key
 * @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>.)
 */
// eg1: hashMap.put(0, "a0");
// eg2: hashMap.put(1, "a1");
// eg3: hashMap.put(16, "a16");
// eg4: hashMap.put(32, "a32");
//eg5:hashMap.put(48,"a48");hashMap.put(64,"a64");hashMap.put(80,"a80"); hashMap.put(96, "a96");hashMap.put(112, "a112");
// eg6: hashMap.put(128, "a128");
public V put(K key, V value) {
	// 我们本次使用的数二进制位数都是低于十六位的,所以都是原数输出,即输入1,hash(1)等于1
    return putVal(hash(key), key, value, false, true);
}

hash方法
在这里插入图片描述

/**
* Computes key.hashCode() and spreads (XORs) higher bits of hash
* to lower.  Because the table uses power-of-two masking, sets of
* hashes that vary only in bits above the current mask will
* always collide. (Among known examples are sets of Float keys
* holding consecutive whole numbers in small tables.)  So we
* apply a transform that spreads the impact of higher bits
* downward. There is a tradeoff between speed, utility, and
* quality of bit-spreading. Because many common sets of hashes
* are already reasonably distributed (so don't benefit from
* spreading), and because we use trees to handle large sets of
* collisions in bins, we just XOR some shifted bits in the
* cheapest possible way to reduce systematic lossage, as well as
* to incorporate impact of the highest bits that would otherwise
* never be used in index calculations because of table bounds.
*/
// egx: key="k1"
// eg1: key=0
static final int hash(Object key) {
   int h;
   /**
    * 按位异或运算(^):两个数转为二进制,然后从高位开始比较,如果相同则为0,不相同则为1。
    *
    * 扰动函数————(h = key.hashCode()) ^ (h >>> 16) 表示:
    * 	>>> : 无符号右移,忽略符号位,空位都以0补齐
    *      将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位进行扰动。
    */
}

扰动函数————(h = key.hashCode()) ^ (h >>> 16)
我们的例子采用的key都是Integer类型,是因为Integer类型的hashCode值即为他本身
不使用String的原因是因为没有办法准确的插入到某个位置
Integer的hashCode()方法

/**
 * Returns a hash code for this {@code Integer}.
 */
@Override
public int hashCode() {
    return Integer.hashCode(value);
}

/**
 * Returns a hash code for a {@code int} value; compatible with
 */
public static int hashCode(int value) {
    return value;
}

String的hashCode()

/**
* 计算String的哈希值
*
* 假设 n=3
* i=0 -> h = 31 * 0 + val[0]
* i=1 -> h = 31 * (31 * 0 + val[0]) + val[1]
* i=2 -> h = 31 * (31 * (31 * 0 + val[0]) + val[1]) + val[2]
*        h = 31*31*31*0 + 31*31*val[0] + 31*val[1] + val[2]
*        h = 31^(n-1)*val[0] + 31^(n-2)*val[1] + val[2]
* 即:
*    s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
*/
// eg1: key="k1"
public int hashCode() {
   // eg1: hash=0 h=0
   int h = hash;
   // eg1: value={'k','1'} value.length=2
   /** 只有第一次计算hash值时,才进入下面逻辑中。此后调用hashCode方法,都直接返回hash*/
   if (h == 0 && value.length > 0) {
       char val[] = value;

       for (int i = 0; i < value.length; i++) {
           // eg1: val[0]=107 val[1]=49
           h = 31 * h + val[i];
       }
       // eg1: 31(31*0+107)+49=3366
       hash = h;
   }
   return h;
}

putVal(hash(key), key, value, false, true)
在这里插入图片描述

/**
* 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
*/
// eg1: hash=0 key=0 value="a0" onlyIfAbsent=false evict=true
// eg2: hash=1 key=1 value="a1" onlyIfAbsent=false evict=true
// eg3: hash=16 key=16 value="a16" onlyIfAbsent=false evict=true
// eg4: hash=32 key=32 value="a32" onlyIfAbsent=false evict=true
// eg5: 由于执行步骤与eg4相似,故略过。
// eg6: hash=128 key=128 value="a128" onlyIfAbsent=false evict=true
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
                   /** 如果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;
}
// 存储Node数组。
transient Node<K, V>[] table;

n = (tab = resize()).length;
resize()
在这里插入图片描述
在这里插入图片描述

/**
* Initializes or doubles table size.  If null, allocates in
* accord with initial capacity target held in field threshold.
* Otherwise, because we are using power-of-two expansion, the
* elements from each bin must either stay at same index, or move
* with a power of two offset in the new table.
*
* @return the table 指的就是我们hashMap中的纵向表
*
* table扩容
*
* 常量命名解释:
* Tab——>Table 表
* Cap——>Capacity 容量
* Thr——>Threshold 阈值,即达到这个值就应该开始扩容
*/
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
       // 即我的表容量为16,但我的阀值为12就是说,当我集合中的元素大小为12的时候我就要去做一个扩容操作,而不是等到16再去进行扩容。这里就是一个提前扩容的机制
       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;
}

最终结论:即当Node链表大于8个Node且表tab的长度大于64才转变为红黑树
treeifyBin(tab, hash)

/**
* Replaces all linked nodes in bin at index for given hash unless
* table is too small, in which case resizes instead.
*/
// eg6: hash=128
// tab[0]=Node(0, 0, "a0", nodeRef)——>Node(16, 16, "a16", nodeRef)——>Node(32, 32, "a32", nodeRef)——>Node(48, 48, "a48",nodeRef)——>Node(64, 64, "a64", node)——>Node(80, 80, "a80", node)——>Node(96, 96, "a96", node)——>Node(112, 112, "a112", node)
// tab[1]=Node(1, 1, "a1", null)
final void treeifyBin(Node<K, V>[] tab, int hash) {
   int n;
   int index;
   Node<K, V> e;
   //  eg6: tab !=null, tab.length=16
   if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) { /** 当表tab的长度小于64时,只扩展数组大小,不转换为树 */
       //  eg6: 执行resize()
       resize();
   } else if ((e = tab[index = (n - 1) & hash]) != null) { /** 如果新增的node要插入的数组位置已经有node存在了,取出该位置的node节点*/
       TreeNode<K, V> hd = null; /** 头节点*/
       TreeNode<K, V> tl = null; /** 尾节点*/
       do {
           /** 将Node转化为TreeNode——> new TreeNode<>(p.hash, p.key, p.value, next);*/
           TreeNode<K, V> p = replacementTreeNode(e, null);

           /** 将每个Node转换为TreeNode,并且用prev和next指针进行链接,并以hd为头节点*/
           if (tl == null) {
               hd = p;
           } else {
               p.prev = tl;
               tl.next = p;
           }
           tl = p;
       } while ((e = e.next) != null);

       /** 如果头节点hd不为null,则进行树型化操作*/
       if ((tab[index] = hd) != null) {
           hd.treeify(tab);
       }
   }
}
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 18
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值