Java 集合之ArrayList

1.回顧

在上一篇 咱們介紹了java集合的總體架構,爲了複習方便請從新看下圖java

Colletion 有List Set等子接口 而每一個子接口又有具體的實現類,本文要講的ArrayList就是List的一種實現。List可存儲有序可重複的元素,那麼可知ArrayList也是。相反Set倒是無序不可重複的。數組

2.結構

那麼咱們開始重點看ArrayList,經過idea可得下圖bash

由上圖知架構

實現RandomAccess接口:能夠經過下標序號快速訪問dom

實現了Cloneable,能被克隆ide

實現了Serializable,支持序列化函數

再看類中方法以下源碼分析

可見ArrayList除了實現類Collection接口方法外 還多了許多重載多方法 例如ui

void add(int index, E element)
boolean addAll(int index, Collection<? extends E> c)
E get(int index)
int indexOf(Object o)
int lastIndexOf(Object o)
E remove(int index)
E set(int index, E element)
List<E> subList(int fromIndex, int toIndex)
複製代碼

上面的方法 顧名思義均可以猜出來 因爲ArrayList是有序可重複的,其中維護了一個索引index 固能夠以指定索引index來進行更多的操做,例如獲取指定索引位置的元素,刪除指定索引位置的元素,截取某個索引範圍的全部元素等等this

3.源碼分析

一.成員變量

private static final long serialVersionUID = 8683452581122892189L;
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData; // non-private to simplify nested class access
private int size;
複製代碼
  • DEFAULT_CAPACITY默認容量是10
  • EMPTY_ELEMENTDATA 數組
  • DEFAULTCAPACITY_EMPTY_ELEMENTDATA
  • elementData 存放元素
  • size 元素個數

二.構造函數

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);
        }
    }
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    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;
        }
    }
複製代碼

有三個構造函數 分析代碼可知可初始化時傳遞一個int值指定容量,也能夠不傳默認10的容量 還能夠傳遞一個指定Collection 來初始化 其中第三個指定Collection來初始化較長,無非就是先把集合轉化成數組 而後把元素複製到list中去來完成初始化

三.經常使用方法

新增

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

其中調用 ensureCapacityInternal 方法

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

        ensureExplicitCapacity(minCapacity);
    }
複製代碼

再調用 ensureExplicitCapacity 方法

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
複製代碼

又調用 grow 方法

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);
    }
複製代碼

總結以上即是新增前須要肯定容量,噹噹前數組容量不夠時就須要擴容,而後調Arrays.copyOf()建立一個新的數組並將數據拷貝到新數組中,且把引用賦值給elementData

刪除remove

public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        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;
    }
    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++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
複製代碼

兩種重載方法 先檢查範圍 而後拿到被刪的元素 而後把被刪元素後到元素往前移動 複製到目標數組 而後返回被刪元素

修改set

public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }
複製代碼

這段代碼比較簡單 範圍檢查和從新賦值

獲取get

public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }
複製代碼

這個估計都不用我說把

4.總結

經過結構源碼都分析咱們知道,ArrayList 底層就是經過數組來實現,添加的時候檢查容量不夠就擴容,而後賦值 刪除時則把被刪元素後往前移動 更新則比較簡潔明白。

相關文章
相關標籤/搜索