Java集合類之ArrayList

學習Java的集合類java

(1)成員變量以及初始化數組

private static final int DEFAULT_CAPACITY = 10; private static final Object[] EMPTY_ELEMENTDATA = {}; private transient Object[] elementData; private int size;

 默認的大小爲10。dom

EMPTY_ELEMENTDATA是用於無參初始化,即一個等於null的對象數組。ide

elemenData則用於有參初始化的變量,也是咱們下面操做的主體對象。函數

下面看看有參初始化的源碼:學習

public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; }

此處初始化一個大小爲initialCapacity的對象數組this

由初始化的過程能夠看出:ArrayList是基於動態數組實現的。spa

 

(2)經常使用操做code

// Collection中定義的API
boolean             add(E object)
boolean             addAll(Collection<? extends E> collection)
void                clear()
boolean             contains(Object object)
boolean             containsAll(Collection<?> collection)
boolean             equals(Object object)
int                 hashCode()
boolean             isEmpty()
Iterator<E>         iterator()
boolean             remove(Object object)
boolean             removeAll(Collection<?> collection)
boolean             retainAll(Collection<?> collection)
int                 size()
<T> T[]             toArray(T[] array)
Object[]            toArray()
// AbstractCollection中定義的API
void                add(int location, E object)
boolean             addAll(int location, Collection<? extends E> collection)
E                   get(int location)
int                 indexOf(Object object)
int                 lastIndexOf(Object object)
ListIterator<E>     listIterator(int location)
ListIterator<E>     listIterator()
E                   remove(int location)
E                   set(int location, E object)
List<E>             subList(int start, int end)
// ArrayList新增的API
Object               clone()
void                 ensureCapacity(int minimumCapacity)
void                 trimToSize()
void                 removeRange(int fromIndex, int toIndex)

Add方法用於添加一個元素到當前列表的末尾
AddRange方法用於添加一批元素到當前列表的末尾
Remove方法用於刪除一個元素,經過元素自己的引用來刪除
RemoveAt方法用於刪除一個元素,經過索引值來刪除
RemoveRange用於刪除一批元素,經過指定開始的索引和刪除的數量來刪除
Insert用於添加一個元素到指定位置,列表後面的元素依次日後移動
InsertRange用於從指定位置開始添加一批元素,列表後面的元素依次日後移動對象

Clear方法用於清除現有全部的元素
Contains方法用來查找某個對象在不在列表之中

TrimSize用於將ArrayList固定到實際元素的大小,當動態數組元素肯定不在添加的時候,能夠調用這個方法來釋放空餘的內存。
ToArray方法把ArrayList的元素Copy到一個新的數組中。

此處咱們特殊須要看一下indexof的源碼:

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;
}
View Code

此處能夠看出,indexof是經過for循環實現的,也就是說要遍歷一遍對象數組,相似的contains方法也是經過for循環來判斷元素是否包含在內。

因此這類方法的效率是極其低下的,沒必要本身寫for循環來得快,若是須要頻繁使用此類快速鍵值查找的功能,建議使用HashMap.

 

(3)大小的動態調整

從add()方法看起: 

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
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++;
}
add(int index, E element)

ensureCapacityInternal()函數會調用ensureExplicitCapacity()函數,檢測後若是肯定須要擴容,則調用grow()函數

/*
最大的容量。
一些虛擬機可能會在一個數組的頭部有幾位保留信息,因此是Integer.MAX_VALUE - 8
若是想創造大小超過這個極限值的ArrayList會報錯:OutOfMemoryError
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/*
增加容量以保證能夠容納當前全部元素的最小長度要求。
@param minCapacity 當前的最小容量需求。
*/
private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}

分析最關鍵的grow()函數可知:

關鍵:newCapacity = oldCapacity + (oldCapacity >> 1);

即newCapacity是oldCapacity的3倍

接下檢查此時的大小是否合理,是否小於最小界,大於最大界(最大界定義處有一個減8的操做,是用來適應不一樣的虛擬機規範,有的虛擬機在數組的頭部留出幾位來存儲一些相關信息)

調整大小後經過複製操做來重造一個數組返回給elementData

 

 (4)遍歷方式

第一,隨機訪問,經過索引獲取元素。ArrayList實現了RandomAccess接口。下面是get()方法源碼

public E get(int index) {
    rangeCheck(index);
    checkForComodification();
    return ArrayList.this.elementData(offset + index);
}

第二,for循環,以Integer元素爲例

Integer value = null;
for (Integer integ:list) {
    value = integ;
}

第三,經過迭代器(Iterator)去遍歷,以Integer元素爲例

Integer value = null;
Iterator iter = list.iterator();
while (iter.hasNext()) {
    value = (Integer)iter.next();
}

這三種方法中,隨機訪問的訪問最快,迭代器的方法最慢

 

(5)序列化

ArrayList實現了java.io.Serializable接口,能夠進行序列化,源碼以下

/**
* Save the state of the <tt>ArrayList</tt> instance to a stream (that
* is, serialize it).
*
* @serialData The length of the array backing the <tt>ArrayList</tt>
*             instance is emitted (int), followed by all of its elements
*             (each an <tt>Object</tt>) in the proper order.
*/
private void writeObject(java.io.ObjectOutputStream s)
    throws java.io.IOException{
    // Write out element count, and any hidden stuff
    int expectedModCount = modCount;
    s.defaultWriteObject();

    // Write out size as capacity for behavioural compatibility with clone()
    s.writeInt(size);

    // Write out all elements in the proper order.
    for (int i=0; i<size; i++) {
        s.writeObject(elementData[i]);
    }

    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

/**
* Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
* deserialize it).
*/
private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    elementData = EMPTY_ELEMENTDATA;

    // Read in size, and any hidden stuff
    s.defaultReadObject();

    // Read in capacity
    s.readInt(); // ignored

    if (size > 0) {
        // be like clone(), allocate array based upon size not capacity
        ensureCapacityInternal(size);

        Object[] a = elementData;
        // Read in all elements in the proper order.
        for (int i=0; i<size; i++) {
            a[i] = s.readObject();
        }
    }
}
View Code
相關文章
相關標籤/搜索