Step00--ArrayList

ArrayList

學習集合的方法:

  • 看繼承結構
  • 看構造方法
  • 看常用方法

在這裏插入圖片描述
吐槽一下:IDEA的UML圖表示的有點膚淺,帶三角的實線代表繼承某個類,而帶三角的虛線表示實現某個接口。

ArrayList是AbstractList的子類,實現了3個標識接口(即沒有任何方法),

  • RandomAccess實現類支持隨機訪問
  • Cloneable實現類支持克隆,需要重寫clone方法
  • Serializable實現類支持序列化,需要重寫readObject,writeObject方法

成員變量

//serialVersionUID是用來驗證版本是否一致的
private static final long serialVersionUID = 8683452581122892189L;
//默認容量爲10
private static final int DEFAULT_CAPACITY = 10;
//空對象數組
private static final Object[] EMPTY_ELEMENTDATA = {};
//默認空對象數組
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//ArrayList的底層用對象數組實現
transient Object[] elementData; // non-private to simplify nested class access
//元素個數
private int size;

內部類

//實現了Iterator接口,有hasNext,next方法
private class Itr implements Iterator<E>
//實現了ListIterator接口,增加了hasPrevious,previous,previousIndex方法,即逆序遍歷的方法,還有nextIndex
private class ListItr extends Itr implements ListIterator<E> 
//返回當前列表的部分視圖,爲什麼叫視圖呢?我想是因爲沒有新建一個列表,而是用指針劃定範圍,故稱視圖,範圍是[),
private class SubList extends AbstractList<E> implements RandomAccess 
static final class ArrayListSpliterator<E> implements Spliterator<E> 

構造函數

/**
 * 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);
    }
}

/**
 * Constructs an empty list with an initial capacity of ten.
 */
//無參構造器:則創建一個空對象數組
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

/**
 * 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) {
    //將指定集合的元素放進對象數組,再賦值給elementData
    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;
    }
}

add,addAll方法

/**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
//如果使用無參構造器,則
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

/**
     * Inserts the specified element at the specified position in this
     * list. Shifts the element currently at that position (if any) and
     * any subsequent elements to the right (adds one to their indices).
     *
     * @param index index at which the specified element is to be inserted
     * @param element element to be inserted
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
public void add(int index, E element) {
    rangeCheckForAdd(index);

    ensureCapacityInternal(size + 1);  // Increments modCount!!
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;
    size++;
}

/**
     * Appends all of the elements in the specified collection to the end of
     * this list, in the order that they are returned by the
     * specified collection's Iterator.  The behavior of this operation is
     * undefined if the specified collection is modified while the operation
     * is in progress.  (This implies that the behavior of this call is
     * undefined if the specified collection is this list, and this
     * list is nonempty.)
     *
     * @param c collection containing elements to be added to this list
     * @return <tt>true</tt> if this list changed as a result of the call
     * @throws NullPointerException if the specified collection is null
     */
public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;
    return numNew != 0;
}

/**
     * Inserts all of the elements in the specified collection into this
     * list, starting at the specified position.  Shifts the element
     * currently at that position (if any) and any subsequent elements to
     * the right (increases their indices).  The new elements will appear
     * in the list in the order that they are returned by the
     * specified collection's iterator.
     *
     * @param index index at which to insert the first element from the
     *              specified collection
     * @param c collection containing elements to be added to this list
     * @return <tt>true</tt> if this list changed as a result of the call
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @throws NullPointerException if the specified collection is null
     */
//其實與add方法差不多,只是不再默認添加到末尾了,而是指定下標,假設index爲0,
//則要移動的元素個數爲:size-index,考慮極端情況:添加到末尾的,則是不要移動元素,
public boolean addAll(int index, Collection<? extends E> c) {
    rangeCheckForAdd(index);

    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount

    int numMoved = size - index;
    if (numMoved > 0)
        System.arraycopy(elementData, index, elementData, index + numNew,
                         numMoved);
//還要把指定集合的元素拷貝到空出的位置來
    System.arraycopy(a, 0, elementData, index, numNew);
    size += numNew;
    return numNew != 0;
}

調整數組容量

public void ensureCapacity(int minCapacity) {
    int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
        // any size if not default element table
        ? 0
        // larger than default for default empty table. It's already
        // supposed to be at default size.
        : DEFAULT_CAPACITY;

    if (minCapacity > minExpand) {
        ensureExplicitCapacity(minCapacity);
    }
}
//計算容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    //先判斷當前對象數組是否爲空對象數組,使用無參構造器創建列表時,對象數組爲空
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //是的話,從最小容量與默認容量中挑出最大值,即從1,10兩個數中挑出10
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}
//確保內部容量
private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//確保實際容量
private void ensureExplicitCapacity(int minCapacity) {
    //modCount採用fast-fail,即併發訪問非線程安全對象時,儘快失敗,拋出異常
    //什麼時候modcount會++?就是發生結構性修改的時候,如添加,刪除元素時,查詢和更新元素不算,將元素置爲null也算刪除元素
    modCount++;

    // overflow-conscious code
    //最小容量大於比對象數組長度,如10>0,則擴容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

/**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
private void grow(int minCapacity) {
    // overflow-conscious code
    //保存舊容量
    int oldCapacity = elementData.length;
    //新容量爲舊容量的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    //如果新容量依舊小於最小容量,如0<10
    if (newCapacity - minCapacity < 0)
        //則新容量被賦值爲最小容量
        newCapacity = minCapacity;
    //如果新容量大於最大數組容量
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        //則最大化數組容量
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    //將對象數組拷貝到容量爲新容量的新對象數組裏去,同時更新elementData
    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;
}

大量數據插入

/**
 * Increases the capacity of this <tt>ArrayList</tt> instance, if
 * necessary, to ensure that it can hold at least the number of elements
 * specified by the minimum capacity argument.
 *
 * @param   minCapacity   the desired minimum capacity
 */
//大量數據插入,使用ensureCapacity來減少擴容的次數,提高效率,前提是我們要提前知道容量的數量級
public void ensureCapacity(int minCapacity) {
    int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
        // any size if not default element table
        ? 0
        // larger than default for default empty table. It's already
        // supposed to be at default size.
        : DEFAULT_CAPACITY;

    if (minCapacity > minExpand) {
        ensureExplicitCapacity(minCapacity);
    }
}

get方法

/**
 * 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}
 */
public E get(int index) {
    //先檢查下標是否越界
    rangeCheck(index);

    return elementData(index);
}

// Positional Access Operations
@SuppressWarnings("unchecked")
E elementData(int index) {
    return (E) elementData[index];
}
//需要下標基於0到(元素個數-1)之間
private void rangeCheck(int index) {
    if (index < 0 || index >= this.size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

set方法

/**
 * 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) {
    rangeCheck(index);

    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

remove,removeAll方法

/**
 * Removes the element at the specified position in this list.
 * Shifts any subsequent elements to the left (subtracts one from their
 * indices).
 *
 * @param index the index of the element to be removed
 * @return the element that was removed from the list
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E remove(int index) {
    rangeCheck(index);

    modCount++;
    E oldValue = elementData(index);
//計算要移動的元素個數,即size-index-1,你可以想象刪除下標爲0的元素,則要移動的元素爲size-1
    int numMoved = size - index - 1;
    if (numMoved > 0)
        //指明源數組,目標數組,還有各自的偏移量,最後是指明長度
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    //置空讓垃圾回收機制更加快的回收它
    elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}

/**
 * Removes the first occurrence of the specified element from this list,
 * if it is present.  If the list does not contain the element, it is
 * unchanged.  More formally, removes the element with the lowest index
 * <tt>i</tt> such that
 * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
 * (if such an element exists).  Returns <tt>true</tt> if this list
 * contained the specified element (or equivalently, if this list
 * changed as a result of the call).
 *
 * @param o element to be removed from this list, if present
 * @return <tt>true</tt> if this list contained the specified element
 */
//移除滿足條件的第一個元素
public boolean remove(Object o) {
    //分一下空與非空即可
    if (o == null) {
        for (int index = 0; index < size; index++)
            if (elementData[index] == null) {
                fastRemove(index);
                return true;
            }
    } else {
        for (int index = 0; index < size; index++)
            //需要重寫equals方法
            if (o.equals(elementData[index])) {
                fastRemove(index);
                return true;
            }
    }
    return false;
}
/**
     * Removes from this list all of its elements that are contained in the
     * specified collection.
     *
     * @param c collection containing elements to be removed from this list
     * @return {@code true} if this list changed as a result of the call
     * @throws ClassCastException if the class of an element of this list
     *         is incompatible with the specified collection
     * (<a href="Collection.html#optional-restrictions">optional</a>)
     * @throws NullPointerException if this list contains a null element and the
     *         specified collection does not permit null elements
     * (<a href="Collection.html#optional-restrictions">optional</a>),
     *         or if the specified collection is null
     * @see Collection#contains(Object)
     */
public boolean removeAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, false);
}
//只保留與指定集合的交集或刪除與指定集合的交集,
//complement爲true是隻保留與指定集合的交集,如果沒有交集,則elementData元素都被置爲null
//complement爲false則是刪除與指定集合的交集
private boolean batchRemove(Collection<?> c, boolean complement) {
    final Object[] elementData = this.elementData;
    //w用來表示交集的個數
    int r = 0, w = 0;
    boolean modified = false;
    try {
        for (; r < size; r++)
            if (c.contains(elementData[r]) == complement)
                elementData[w++] = elementData[r];
    } finally {
        // Preserve behavioral compatibility with AbstractCollection,
        // even if c.contains() throws.
        if (r != size) {
            System.arraycopy(elementData, r,
                             elementData, w,
                             size - r);
            w += size - r;
        }
        if (w != size) {
            // clear to let GC do its work
            for (int i = w; i < size; i++)
                elementData[i] = null;
            modCount += size - w;
            size = w;
            modified = true;
        }
    }
    return modified;
}
/*
     * Private remove method that skips bounds checking and does not
     * return the value removed.
     */
//跳過邊界檢查,也不返回刪除的值
private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work
}

Arrays.copy方法與System.arrayCopy方法

/**
 * Copies the specified array, truncating or padding with nulls (if necessary)
 * so the copy has the specified length.  For all indices that are
 * valid in both the original array and the copy, the two arrays will
 * contain identical values.  For any indices that are valid in the
 * copy but not the original, the copy will contain <tt>null</tt>.
 * Such indices will exist if and only if the specified length
 * is greater than that of the original array.
 * The resulting array is of the class <tt>newType</tt>.
 *
 * @param <U> the class of the objects in the original array
 * @param <T> the class of the objects in the returned array
 * @param original the array to be copied
 * @param newLength the length of the copy to be returned
 * @param newType the class of the copy to be returned
 * @return a copy of the original array, truncated or padded with nulls
 *     to obtain the specified length
 * @throws NegativeArraySizeException if <tt>newLength</tt> is negative
 * @throws NullPointerException if <tt>original</tt> is null
 * @throws ArrayStoreException if an element copied from
 *     <tt>original</tt> is not of a runtime type that can be stored in
 *     an array of class <tt>newType</tt>
 * @since 1.6
 */
//Arrays.copy方法底層還是用System.arrayCopy方法實現的,
//Arrays.copy方法有新建數組,而直接用System.arraycopy方法則是沒有新建數組
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}

技巧

IDEA選中多行的方式:alt+shift

可用調試的方式來分析源代碼執行邏輯

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章