Exploring the source code of ArrayList: the implementation behind Java dynamic array



1. Member variables

Readers need to read the member variables of the source code first, and look at them familiarly, which will help the understanding of the source code later

private static final long serialVersionUID = 8683452581122892189L;

    /**
     * 默认初始容量大小
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 空数组(用于空实例)。
     */
    private static final Object[] EMPTY_ELEMENTDATA = {
    
    };

     //用于默认大小空实例的共享空数组实例。
      //我们把它从EMPTY_ELEMENTDATA数组中区分出来,以知道在添加第一个元素时容量需要增加多少。
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
    
    };

    /**
     * 存储ArrayList元素的数组缓冲区
     */
    transient Object[] elementData; 

    /**
     * ArrayList 所包含的元素个数
     */
    private int size;

Two, the constructor

1. Default constructor

/**
 *默认构造函数,使用初始容量10构造一个空列表(无参数构造)
 */
public ArrayList() {
    
    
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

When an ArrayList is created with a parameterless construction method, an empty array is actually initialized and assigned. At this time, no object is created for it, and the capacity is actually allocated when the operation of adding elements to the array is actually performed. That is, when the first element is added to the array, the capacity of the array is expanded to 10.

2. Constructor with initial capacity parameter

/**
 * 带初始容量参数的构造函数。(用户自己指定容量)
 */
public ArrayList(int initialCapacity) {
    
    
    if (initialCapacity > 0) {
    
    //初始容量大于0
        //创建initialCapacity大小的数组
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
    
    //初始容量等于0
        //创建空数组
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
    
    //初始容量小于0,抛出异常
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

3. Specify the collection element parameter constructor

/**
*构造包含指定collection元素的列表,这些元素利用该集合的迭代器按顺序返回
*如果指定的集合为null,throws NullPointerException。
*/
 public ArrayList(Collection<? extends E> c) {
    
    
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
    
    
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
    
    
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

3. Add() method expansion mechanism

Before entering the core source code expansion mechanism of ArrayList, we first need to have a preliminary understanding of some variables involved in the source code, which will help you gain an in-depth understanding of the source code

  1. minCapacity: the minimum capacity required by the array
  2. elementData: Array buffer that stores ArrayList elements

insert image description here

public boolean add(E e) {
    
    
   ensureCapacityInternal(size + 1);  // size = 0
   elementData[size++] = e;
   return true;
}
private void ensureCapacityInternal(int minCapacity) {
    
    //minCapacity = 1
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));//elementData = {}
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    
    
    //判断elementData是否为空数组
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
    
    //DEFAULTCAPACITY_EMPTY_ELEMENTDATA =  {}
        return Math.max(DEFAULT_CAPACITY, minCapacity);//DEFAULT_CAPACITY = 10;minCapacity = 1
    }
    return minCapacity;
}
private void ensureCapacityInternal(int minCapacity) {
    
    //minCapacity = 1
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));//ensureExplicitCapacity(10)
}
private void ensureExplicitCapacity(int minCapacity) {
    
    //minCapacity = 10
    modCount++;

    if (minCapacity - elementData.length > 0)//elementData.length = 0
        grow(minCapacity);
}
private void grow(int minCapacity) {
    
    //minCapacity = 10
    int oldCapacity = elementData.length;//oldCapacity = 0
    int newCapacity = oldCapacity + (oldCapacity >> 1);//newCapacity  = 1.5*oldCapacity = 0
    if (newCapacity - minCapacity < 0)//minCapacity = 10
        newCapacity = minCapacity;//newCapacity = 10
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    //利用Arrays.copyOf()方法进行扩容
    elementData = Arrays.copyOf(elementData, 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;
 }
  1. Add a new element, the minimum capacity required at this time isminCapacity = size+1
  2. First determine elementDatawhether the underlying array is an empty array
    • If it is an empty array, update it minCapacityto the default capacity of 10,
    • If not an empty array, make minCapacityno changes to
  3. Determine whether the required minimum capacity minCapacityis greater than the length of the buffer array elementData:
    • If it is larger, expand the capacity grow(),
    • otherwise do not process
  4. During capacity expansion grow(), first elementDataexpand the length to 1.5 times the original length, and then judge the expanded length elementDataand the required minimum capacityminCapacity
    • If the length of after expansion elementDatais still smaller than minCapacitythe length of , it is still not enough. At this time, minCapacitythe length of is directly assigned toelementData
    • Otherwise, go directly to the next step
  5. Finally, it is necessary to judge elementDatawhether the length of is beyond the maximum valueMAX_ARRAY_SIZE
    • If the maximum value is exceeded, see if the required minimum capacity minCapacityis greater than the maximum valueInteger.MAX_VALUE
    • If not, expand the length of the array to the maximum value of the array MAX_ARRAY_SIZE, if yes, returnInteger.MAX_VALUE

4. Scene analysis

1. For the ensureExplicitCapacity() method

1.1 When adding the first element to ArrayList

When we want to addenter the first element to ArrayList, elementData.lengthit is 0 (because it is still an empty list), because ensureCapacityInternal()the method is executed, so minCapacityit is 10 at this time. At this time, minCapacity - elementData.length > 0it is established, so it will enter grow(minCapacity)the method.

1.2 When adding the second element

When the second element is added, minCapacityit is 2. At this time, elementData.length(容量)the capacity is expanded to 10 after adding the first element. At this time, minCapacity - elementData.length > 0it is not true, so the method will not be entered (executed) grow(minCapacity).
When adding the 3rd, 4th... to the 10th element, growthe method will still not be executed, and the capacity of the array is 10.

1.3 until the 11th element is added

minCapacity(为 11)is greater than elementData.length(is 10). Enter growthe method to expand.

2. For the grow() method:

2.1 When adding the first element

oldCapacityis 0, the first if judgment is established after comparison, newCapacity = minCapacity(为 10). But the second if judgment will not be true, that is, newCapacityis not MAX_ARRAY_SIZEgreater than , it will not enter hugeCapacitythe method. The capacity of the array is 10, return true in the add method, and the size is increased to 1.

2.2 When the 11th element of add enters the grow method

newCapacityis 15, the ratio minCapacity(为 11)is larger, and the first if judgment is not established. If the new capacity is not greater than the maximum size of the array, it will not enter hugeCapacitythe method. The capacity of the array is expanded to 15, return true in the add method, and the size is increased to 11. And so on...

5. Experience

  1. Variables are understood as the minimum capacityminCapacity required by the underlying array when we add elements into the ArrayList collection
  2. Variables elementData.lengthare understood as we add elements into the ArrayList collection, the maximum capacity of the underlying array
  3. When the minimum capacity minCapacity> maximum capacity elementData.length , the capacity expansion mechanism will be triggered.
  4. We always add elements to the ArrayList collection frequently, and developers have thought of this, so in the expansion mechanism of the ArrayList collection, when we add the first element, we directly set it to 10. Here, it can be understood that because we need to add elements frequently in the future, in order not to always trigger the expansion mechanism of the collection, we "lie" that the minimum capacity required is 10, so the system directly sets it minCapacityto elementData.length10

6. Simple flow chart of source code

insert image description here

Guess you like

Origin blog.csdn.net/weixin_52533007/article/details/130638330