ArrayList裡有三種構造函數,對應三種ArrayList的初始化方法。

第一種 容量為空初始化

源代碼:

/**
     * Constructs an empty list with an initial capacity of ten.
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

可使用如下方法初始化:

List<String> fruit = new ArrayList<>();
fruit.add("apple");
fruit.add("pear");

下面,來看一看代碼是如何一步一步執行的。

首先初始化arraylist:

List<String> fruit = new ArrayList<>();

呼叫ArrayList()構造函數執行:

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

結果:this.elementData == {}

note
初始化後的ArrayList,是一個空的集合,容量為0。

當第一次add時,呼叫add(E e),源碼:

    public boolean add(E e) {
        modCount++; /** modCount是為判斷是否有多線程操作某個集合,可忽略*/
        add(e, elementData, size);
        return true;
    }

其中的modCount在非線程安全的LinkedList、LinkedList和HashMap中都存在,為的判斷同一個JVM進程是否有多線程操作某個集合。

此處可忽略,執行add(e, elementData, size),源碼:

    private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)
            elementData = grow();
        elementData[s] = e;
        size = s + 1;
    }

此時s==0,elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA,length==0。

所以if條件為真,呼叫grow()

    private Object[] grow() {
        return grow(size + 1);
    }

呼叫grow(int minCapacity),執行grow(1)

    private Object[] grow(int minCapacity) {
        int oldCapacity = elementData.length;/** oldCapacity==0*/
        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            /** 條件不成立,跳過,進入else運算*/
            int newCapacity = ArraysSupport.newLength(oldCapacity,
                    minCapacity - oldCapacity, /* minimum growth */
                    oldCapacity >> 1           /* preferred growth */);
            return elementData = Arrays.copyOf(elementData, newCapacity);
        } else {
            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
            /** DEFAULT_CAPACITY==10, minCapacity==1,是上一步傳入的參數*/
        }
    }

條件不成立,跳過,進入else運算。

執行完畢後,elementData = new Object[10]。

即第一次add時,容量變更為10.

note
即第一次add後,容量變更為10。

接著執行add(E e, Object[] elementData, int s) 裡面接下來的代碼

elementData[s] = e;
size = s + 1;

這是第一種ArrayList的初始化方法後面執行的步驟。

第二種 自訂容量初始化

根據實際需要,指定容量初始化。

源碼:

    /**
     * Constructs an empty list with the specified initial capacity.
     *
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

可使用如下方法初始化:

List<String> student = new ArrayList<>(32);
student.add("Bob");
student.add("Peter");

自訂容量初始化的好處是:

  • 減少擴容的次數,提高效率。

第三種 根據現有集合初始化

根據現有的集合初始化。可以將其他集合轉為ArrayList,

源碼:

/**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    public ArrayList(Collection<? extends E> c) {
        Object[] a = c.toArray();
        if ((size = a.length) != 0) {
            if (c.getClass() == ArrayList.class) {
                elementData = a;
            } else {
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
        } else {
            // replace with empty array.
            elementData = EMPTY_ELEMENTDATA;
        }
    }

比如可以將HashSet轉為ArrayList:

Set<String> students = new HashSet<>();
students.add("Bob");
students.add("Alice");

List<String> list = new ArrayList<>(students);

此時,list裡面包含兩個元素Bob和Alice。

如下方法通過Arrays.asList(array)方法構造ArrayList時,也是調用第三種構造函數。

String[] array = {"Bob", "Alice"};
ArrayList<String> students = new ArrayList<>(Arrays.asList(array));

參考: jdk source code