Please go to DobbyKim’s Question of the Day for more questions

A:

Initialize an empty ArrayList with a capacity of 0 for the underlying array and 10 for the underlying array after adding one element.

In ArrayList, the underlying storage of data is an array elementData that supports dynamic scaling:

transient Object[] elementData; // non-private to simplify nested class access
Copy the code

First, we check our answer by getting the elementData field by reflection:

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        ArrayList<Integer> list = new ArrayList<>();
        System.out.println("elementData length : " + getArrayListElementDataLength(list));

        list.add(1);

        System.out.println("elementData length : " + getArrayListElementDataLength(list));
    }

    private static int getArrayListElementDataLength(ArrayList list) throws NoSuchFieldException, IllegalAccessException {
        Class<? extends List> listClass = list.getClass();
        Field field = listClass.getDeclaredField("elementData");
        field.setAccessible(true);
        Object[] elementData = (Object[]) field.get(list);
        returnelementData.length; }}Copy the code

The program runs, and the output is:

elementData length : 0
elementData length : 10
Copy the code

Reasons explained:

First, let’s look at the no-argument constructor for ArrayList:

/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList(a) {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
Copy the code

When we initialize an ArrayList with no specified capacity, the constructor simply assigns elementData to an empty array.

Let’s look at the add method for ArrayList:

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
Copy the code

We see that every time we add an element to the ArrayList, we execute a method called ensureCapacityInternal, which is used to make sure that every time we add an element to the ArrayList, the underlying array elementData is large enough to go into that method, We see that the first line of code executes a judgment statement:

if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
    minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
Copy the code

When the elementData array is empty, minCapacity is assigned to DEFAULT_CAPACITY (10) and the one with the larger minCapacity; Add an element where minCapacity is 1 and DEFAULT_CAPACITY is 10.

/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
Copy the code

So, after the first addition to an empty ArrayList, the underlying elementData becomes an array of length 10.