1. 程式人生 > >Java中的集合之ArrayList,Vector和Stack

Java中的集合之ArrayList,Vector和Stack

這三個集合型別,其底層都是陣列實現的。討論集合關注的問題:

  1. 底層資料結構
  2. 增刪改查方式
  3. 初始容量,擴容方式,擴容時機
  4. 執行緒安全與否
  5. 是否允許空,是否允許重複,是否有序

ArrayList

ArrayList是實現List介面的動態陣列。實現了所有可選列表操作,並允許包括 null 在內的所有元素。除了實現 List 介面外,此類還提供一些方法來操作內部用來儲存列表的陣列的大小。

每個陣列都有一個容量,由一個數組維護,初始的容量為10(在第一個元素新增進來時擴容),也可以在初始化new操作時給定。ArrayList繼承自AbstractList,實現了List,RandomAccess,Cloneable,.Serializable介面。

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY =
10; /** * Shared empty array instance used for empty instances. */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * Shared empty array instance used for default sized empty instances. We * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when * first element is added. */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

每次新增新的元素時:先判斷合法性,會判斷陣列的長度,當超過當前的容量大小時,則會擴容一個新的1.5倍的陣列,使用Arrays.copyOf將物件複製到新陣列中。內部陣列elementData使用transient修飾,即進行序列化時,只複製有值的內容,可以節省空間。還可以插入到制定的位置下,同樣操作,使用System.copyOf操作,Arrays.copyOf最終呼叫的也是該方法。刪除也會拷貝,清空則是置為null。

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++;
}
//擴容
 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);
    }

ArrayList的所有方法都沒有加鎖或同步控制,所以是非線性安全的。可以在建立時,使用Collection.synchronizedList使其對外執行緒同步。內建一個modCount進行控制,對內部陣列進行了增刪改動後,該值會++,後續使用迭代器時判斷與expectedModCount不相同則丟擲異常。“Fast-Fail機制”

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();
        }
    }

 

Vector

Vector是實現了List的動態可變集合。Vector同樣繼承自AbstractList,實現了List,RandomAccess,Cloneable,.Serializable介面。基本和ArrayList類似,內部也是一個物件陣列elementData維護,不過沒有transient,意味著序列化全部內容。

初始化,預設直接為10,不需要第一次載入。另外,除了初始化大小外,還可以制定增長的寬度。

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

    /**
     * Constructs an empty vector so that its internal data array
     * has size {@code 10} and its standard capacity increment is
     * zero.
     */
    public Vector() {
        this(10);
    }

新增元素時,同樣會對modCount++,同時判斷當前的大小,加1時超過容量則進行擴容。如果設定了擴容增量大小則按該值,否則就擴容成原來的兩倍,同樣是使用了System.copyOf進行操作。擴容完畢後進行容量的更新。

 private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        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;
    }

Vector中所有對資料進行修改的方法都加了synchronized修飾,來保證執行緒安全性。

public synchronized E remove(int index) {
        modCount++;
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
        E oldValue = elementData(index);

        int numMoved = elementCount - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--elementCount] = null; // Let gc do its work

        return oldValue;
    }

 

Stack

Stack是一種棧結構,在Java中其繼承自Vector。棧很常見,就是一種先進後出,或者說後進先出的資料結構。Stack使用了Vector中的陣列維護資料結構,在Vector外只實現了pop,push,peek,empty,search5個另外的方法。

同樣地,這些方法基本都是使用synchronized修飾,因此Stack是線性安全的。

public synchronized E pop() {
        E  obj;
        int len = size();
        obj = peek();
        removeElementAt(len - 1);
        return obj;
    }
    /* @return  the object at the top of this stack (the last item
     *          of the <tt>Vector</tt> object).
     * @throws  EmptyStackException  if this stack is empty.
     */
    public synchronized E peek() {
        int     len = size();

        if (len == 0)
            throw new EmptyStackException();
        return elementAt(len - 1);
    }

 

小結:

總的來說,ArrayList實現了RandomAccess,所以隨機訪問快速;但是在進行插入或刪除資料的時候,要使用System.copyOf進行大量的資料拷貝,浪費資源。且ArrayList線性不安全。

Vector同樣可以隨機讀取,和ArrayList類似在增刪資料時涉及大量拷貝,但是優點是線性安全的。

Stack用於一些特定的資料結構需求中。

參考文章