天天看點

ArrayList源碼一覽

ArrayList(線程不安全)

ArrayList是一個其容量能夠動态增長的動态數組

繼承關系

ArrayList源碼一覽
ArrayList源碼一覽

構造方法

ArrayList源碼一覽
是符合collection父接口的規範的
//傳0則設定為預設容量
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);
        }
    }

//把collection中的元素取出來,再放在一個數組中
public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();//這個地方說明引用不能為空,否則會出nullpointer異常
        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;
        }
    }
//ArrayList的toarray,因為底層是用數組存的,是以就是把數組複制一下
 public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }
public static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
    }//這裡T其實就是object,是以上面需要做一個if判斷,其他集合最後可能不是object           

Fail-Fast

重要方法

add

在某個索引處添加元素,或者添加集合,删除元素,都是直接通過數組的複制(System.arrayCopy)來完成而不是元素的移動,可以根據情況決定調用次數
public static native void arraycopy(Object src,  int  srcPos,
                                 Object dest, int destPos,
                                 int length);           
//在傳入index參數的時候,都會對其進行檢查 
private void rangeCheck(int index) 
//在調用add在某個index處插入的方法時采用這個進行檢查
private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
 private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)
            elementData = grow();
        elementData[s] = e;
        size = s + 1;
    }
    }           

search

//從前往後找
public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
//從後往前找
    public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }           

set

//修改該位置的值,傳回原來該位置的值
public E set(int index, E element) {
        rangeCheck(index);
        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }           

Sort方法

根據由指定Comparator引起的順序對該清單進行排序。

使用指定的比較器,此清單中的所有元素必須可以互相比較

如果指定的比較器為null則此清單中的所有元素都必須實作Comparable接口,并且應使用元素的自然順序。

該清單必須是可修改的,但無需調整大小。

public void sort(Comparator<? super E> c) {
        final int expectedModCount = modCount;
        Arrays.sort((E[]) elementData, 0, size, c);
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }
}           

這裡的核心方法其實是Arrays.sort()

public static <T> void sort(T[] a, int fromIndex, int toIndex,
                                Comparator<? super T> c) {
        if (c == null) {
        //根據其對象的自然順序,将指定對象數組的指定範圍按升序排序。 要排序的範圍從索引fromIndex (包括在内)到索引toIndex (不包括在内)。
        // (如果fromIndex==toIndex , fromIndex==toIndex排序的範圍為空。)此範圍中的所有元素必須實作Comparable接口
            sort(a, fromIndex, toIndex);
        } else {
            rangeCheck(a.length, fromIndex, toIndex);
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, fromIndex, toIndex, c);//将被遺棄
            else
                TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
        }
    }           

這裡主要是

sort()

TimSort.sort()

這兩個核心方法,讓我們再看一看他們的實作

  • sort()
//ComparableTimSort
static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) {
        assert a != null && lo >= 0 && lo <= hi && hi <= a.length;

        int nRemaining  = hi - lo;
        if (nRemaining < 2)
            return;  // Arrays of size 0 and 1 are always sorted

        // If array is small, do a "mini-TimSort" with no merges
        if (nRemaining < MIN_MERGE) {
            int initRunLen = countRunAndMakeAscending(a, lo, hi);
            binarySort(a, lo, hi, lo + initRunLen);
            return;
        }           

-TimSort.sort()

//TimSort
static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
                         T[] work, int workBase, int workLen) {
        assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;

        int nRemaining  = hi - lo;
        if (nRemaining < 2)
            return;  // Arrays of size 0 and 1 are always sorted

        // If array is small, do a "mini-TimSort" with no merges
        if (nRemaining < MIN_MERGE) {
            int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
            binarySort(a, lo, hi, lo + initRunLen, c);
            return;
        }           

發現沒有,這兩個方法的實作幾乎一模一樣,再看一下,不僅如此

ComparableTimSort

TimSort

這兩個類也幾乎一模一樣.

這是源碼給的注釋

This is a near duplicate of TimSort, modified for use with arrays of objects
 that implement Comparable, instead of using explicit comparators.           

最後其實都是調用了

binarySort(a, lo, hi, lo + initRunLen, c)

進行排序

這裡貼出源碼

private static void binarySort(Object[] a, int lo, int hi, int start) {
        assert lo <= start && start <= hi;
        if (start == lo)
            start++;
        for ( ; start < hi; start++) {
            Comparable pivot = (Comparable) a[start];

            // Set left (and right) to the index where a[start] (pivot) belongs
            int left = lo;
            int right = start;
            assert left <= right;
            /*
             * Invariants:
             *   pivot >= all in [lo, left).
             *   pivot <  all in [right, start).
             */
            while (left < right) {
                int mid = (left + right) >>> 1;
                if (pivot.compareTo(a[mid]) < 0)
                    right = mid;
                else
                    left = mid + 1;
            }
            assert left == right;

            /*
             * The invariants still hold: pivot >= all in [lo, left) and
             * pivot < all in [left, start), so pivot belongs at left.  Note
             * that if there are elements equal to pivot, left points to the
             * first slot after them -- that's why this sort is stable.
             * Slide elements over to make room for pivot.
             */
            int n = start - left;  // The number of elements to move
            // Switch is just an optimization for arraycopy in default case
            switch (n) {
                case 2:  a[left + 2] = a[left + 1];
                case 1:  a[left + 1] = a[left];
                         break;
                default: System.arraycopy(a, left, a, left + 1, n);
            }
            a[left] = pivot;
        }
    }           

将裡面的元素轉換成數組

//實際上經過一些預處理之後都會調用 System.arraycopy方法;
public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }
public <T> T[] toArray(T[] a) {
        if (a.length < size)
            // Make a new array of a's runtime type, but my contents:
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }           

擴容

在add元素的時候
  1. 確定最小容量為size+1(所含元素的個數),ensureCapacityInternal(size+1)
  2. 計算出最小容量calculateCapacity(elementData, minCapacity),如果比預設的小就傳回預設的,比預設的大,就傳回自己
  3. ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)),判斷目前數組長度與所需的最小容量
  4. 如果所需最小容量>目前數組長度,調用grow進行擴容
  5. 一般而言根據

    newCapacity = oldCapacity + (oldCapacity >> 1);

    進行擴容
  6. 如果這樣之後數組長度依然不夠,則直接

    newCapacity = minCapacity;

  7. 如果超過了定義的最大數組長度調用

    newCapacity = hugeCapacity(minCapacity);

  8. 最後進行擴容(實際上就是數組的複制)
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        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 = 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. private class Itr implements Iterator<E>
2. private class ListItr extends Itr implements ListIterator<E>
3. private class SubList extends AbstractList<E> implements RandomAccess 
    對外提供subList(int fromIndex, int toIndex)方法           
Itr
An optimized version of AbstractList.Itr

主要作用就是傳回一個他的執行個體作為疊代器

public Iterator<E> iterator() {
        return new Itr();
    }           
ListItr
//這個方法事實上還是調用的下面這個方法
 public ListIterator<E> listIterator() {
        return new ListItr(0);
    }
public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: "+index);
        return new ListItr(index);
    }           
SubList

被用于求子清單的方法

//這個方法ArrayList與SubList均實作了,一模一樣
public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }           

重要屬性

/**
  *預設初始容量為十.
  */
private static final int DEFAULT_CAPACITY = 10;
/**
 * Shared empty array instance used for empty instances.
 */
//這兩個屬性,隻是為了初始化不報空指針異常
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//ArrayList中含有元素的數量
private int size;
//針對數組而言,指數組的長度
int length;
//最大數組位數要比最大整數小8
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//用這個數組來存儲集合中的元素
transient Object[] elementData;