ArrayList array of JDK source code learning series

1. Class inheritance structure

insert image description here

2. Important member variables

/**
 * 数组默认大小.
 */
private static final int DEFAULT_CAPACITY = 10;

 /**
 * 空数组. new ArrayList(0)时使用它
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

 /**
 * 存储具体数据的数组对象
 */
transient Object[] elementData; 

 /**
 * 数组中元素个数 
 */
private int size;

/**
 * 数组被修改次数,对数组添加或者移除元素时 加1
 */
protected transient int modCount = 0;

3. Important methods

3.1 get(int index)

public E get(int index) {
   // 是否越界  
    rangeCheck(index);
   // 直接通过数组下标获取 
    return elementData(index);
}

3.2 add(E e)

public boolean add(E e) {
   // 确保容量够用
    ensureCapacityInternal(size + 1);  
    // 直接在数组后面添加入当前元素e
    elementData[size++] = e;
    return true;
}
 
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // 当前不够位置插入,需要扩容,进入grow方法
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}  


private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    //  oldCapacity >> 1 表示原容量转二进制后右移1位
    // 10 二进制是1010 右移一位即 0101  得到 newCapacity  = 10 + 5,扩容后是原容量的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
     // 如果扩容后比需要的容量小,则取minCapacity
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
      // 是否大于最大范围限制
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    // 扩容后生成一个新数组替换掉原来的
    elementData = Arrays.copyOf(elementData, newCapacity);
}

3.3 add(int index, E e)

public void add(int index, E element) {
   // 检查是否越界
    rangeCheckForAdd(index);
   // 扩容是否需要
    ensureCapacityInternal(size + 1);  // Increments modCount!! 
    // 从数组index位开始往后移动一位,一共移动 size - index个元素
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    // index空出来后写入 要插入的元素
    elementData[index] = element;
    size++;
}

3.4 remove(int index)

public E remove(int index) {
    rangeCheck(index);
    modCount++;
    // 返回当前元素
    E oldValue = elementData(index);
    int numMoved = size - index - 1;
    if (numMoved > 0)
       // 说明要移除的不是最后一位
       //需要将index之后元素都往前移动一位,共移动size - index - 1个元素
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
        // 最后一位设置为null                 
    elementData[--size] = null; 
    return oldValue;
}

3.5 remove(Object o)

public boolean remove(Object o) {
    if (o == null) {
       // 删除null元素的情况
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
       // 非null元素 
        for (int index = 0; index < size; index++)
           // 遍历找到相等元素,然后传入index去移除
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}

private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0)
        // 这里跟remove(index)一样
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // 最后一位设置为null
}

3.6 addAll(Collection<? extends E> c)

public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    // 是否扩容
    ensureCapacityInternal(size + numNew);  // Increments modCount
    // 从原数组末尾开始放入即将要加入的数组c,操作次数为c数组长度,即numNew
    System.arraycopy(a, 0, elementData, size, numNew);
    // 总数 = 原数组长度 + 数组c的长度
    size += numNew;
    return numNew != 0;
}

3.7 addAll(int index, Collection<? extends E> c)

public boolean addAll(int index, Collection<? extends E> c) {
    rangeCheckForAdd(index);
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew); 
     
    int numMoved = size - index;
    if (numMoved > 0)
        // 非插入末尾的情况
        //  原数组index以及之后的元素往后移动到目的位置:index + numNew,一个操作numMoved 个元素
        System.arraycopy(elementData, index, elementData, index + numNew,
                         numMoved);

   // 上面腾出来位置后,腾出位置大小为a数组的元素个数,将新插入的数组a放到原数组中 
    System.arraycopy(a, 0, elementData, index, numNew);
    size += numNew;
    return numNew != 0;
}

4. Maximum length

ArrayList maximum 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
 */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

That is, the maximum length of a signed integer is 2^31 - 1. Here, 8 is subtracted because some jvm array structures will contain header information. The purpose of this is to reduce the probability of memory overflow. In fact, the maximum length can reach Integer.MAX_VALUE.

5. Why use transient modification

We know that variables modified by the transient keyword will not be serialized into byte streams. ArrayList internally rewrites the writeObject() and readObject() methods, so it can also be serialized, but it does not serialize the entire array violently. Yes, because the number of elements actually stored is generally smaller than the size of the array, which can reduce the memory space occupied.

Guess you like

Origin blog.csdn.net/huangdi1309/article/details/123424799