Vector與ArrayList 的理解

  最近在看Vector與ArrayList的源碼,看下他們的區別與聯繫。數組

  1. Vector是線程安全的集合類,ArrayList並非線程安全的類。Vector類對集合的元素操做時都加了synchronized,保證線程安全。
  2. Vector與ArrayList本質上都是一個Object[] 數組,ArrayList提供了size屬性,Vector提供了elementCount屬性,他們的做用是記錄集合內有效元素的個數。與咱們日常調用的arrayList.size()和vector.size()同樣返回的集合內有效元素的個數。
  3. Vector與ArrayList的擴容並不同,Vector默認擴容是增加一倍的容量,Arraylist是增加50%的容量。
  4. Vector與ArrayList的remove,add(index,obj)方法都會致使內部數組進行數據拷貝的操做,這樣在大數據量時,可能會影響效率。
  5. Vector與ArrayList的add(obj)方法,若是新增的有效元素個數超過數組自己的長度,都會致使數組進行擴容。

  先看下他們的源碼是怎麼定義內部數據存儲的:安全

 1 private static final long serialVersionUID = 8683452581122892189L;
 2 
 3     /**
 4      * Default initial capacity.
 5      */
 6     private static final int DEFAULT_CAPACITY = 10;
 7 
 8     /**
 9      * Shared empty array instance used for empty instances.
10      */
11     private static final Object[] EMPTY_ELEMENTDATA = {};
12 
13     /**
14      * The array buffer into which the elements of the ArrayList are stored.
15      * The capacity of the ArrayList is the length of this array buffer. Any
16      * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to
17      * DEFAULT_CAPACITY when the first element is added.
18      */
19     private transient Object[] elementData;
20 
21     /**
22      * The size of the ArrayList (the number of elements it contains).
23      *
24      * @serial
25      */
26     private int size;

這是ArrayList的定義,他首先定義了他的初始化容量爲10less

private static final int DEFAULT_CAPACITY = 10

這裏應該看到了數據存儲是放在Object數組裏的函數

private transient Object[] elementData

 定義了數據的長度size 大數據

The size of the ArrayList (the number of elements it contains)

再看看Vector的定義:this

 1  /**
 2      * The array buffer into which the components of the vector are
 3      * stored. The capacity of the vector is the length of this array buffer,
 4      * and is at least large enough to contain all the vector's elements.
 5      *
 6      * <p>Any array elements following the last element in the Vector are null.
 7      *
 8      * @serial
 9      */
10     protected Object[] elementData;
11 
12     /**
13      * The number of valid components in this {@code Vector} object.
14      * Components {@code elementData[0]} through
15      * {@code elementData[elementCount-1]} are the actual items.
16      *
17      * @serial
18      */
19     protected int elementCount;
20 
21     /**
22      * The amount by which the capacity of the vector is automatically
23      * incremented when its size becomes greater than its capacity.  If
24      * the capacity increment is less than or equal to zero, the capacity
25      * of the vector is doubled each time it needs to grow.
26      *
27      * @serial
28      */
29     protected int capacityIncrement;

 

Vector定義了數組spa

protected Object[] elementData;

有效元素個數線程

protected int elementCount

Vector增加容量,默認0code

protected int capacityIncrement

Vector和ArrayList在元素超過初始大小時擴容是不同的,可是也不像網上說的Vector增加是按一倍增加,我以爲應該加默認兩個字纔對,Vector中的元素個數超過了初始化容量的話,默認確實會增加一倍,請看代碼:component

 1  /**
 2      * The maximum size of array to allocate.
 3      * Some VMs reserve some header words in an array.
 4      * Attempts to allocate larger arrays may result in
 5      * OutOfMemoryError: Requested array size exceeds VM limit
 6      */
 7     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
 8 
 9     private void grow(int minCapacity) {
10         // overflow-conscious code
11         int oldCapacity = elementData.length;
12         int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
13                                          capacityIncrement : oldCapacity);
14         if (newCapacity - minCapacity < 0)
15             newCapacity = minCapacity;
16         if (newCapacity - MAX_ARRAY_SIZE > 0)
17             newCapacity = hugeCapacity(minCapacity);
18         elementData = Arrays.copyOf(elementData, newCapacity);
19     }

代碼裏在判斷增加容量(簡稱增量)參數時若是增量大於0時,是會按增量進行擴容的,不然的話纔會增長一倍的容量到數組中。

而Vector在初始化加載構造函數時,開發人員是能夠指定其增量的大小的,並非必需要根據增長一倍的規則進行增長。仍是看代碼:

 1  public Vector(int initialCapacity, int capacityIncrement) {
 2         super();
 3         if (initialCapacity < 0)
 4             throw new IllegalArgumentException("Illegal Capacity: "+
 5                                                initialCapacity);
 6         this.elementData = new Object[initialCapacity];
 7         this.capacityIncrement = capacityIncrement;
 8     }
 9 
10     /**
11      * Constructs an empty vector with the specified initial capacity and
12      * with its capacity increment equal to zero.
13      *
14      * @param   initialCapacity   the initial capacity of the vector
15      * @throws IllegalArgumentException if the specified initial capacity
16      *         is negative
17      */
18     public Vector(int initialCapacity) {
19         this(initialCapacity, 0);
20     }
21 
22     /**
23      * Constructs an empty vector so that its internal data array
24      * has size {@code 10} and its standard capacity increment is
25      * zero.
26      */
27     public Vector() {
28         this(10);
29     }

能夠看到在構造函數中已經代表,能夠指定其增量的大小,若是沒有指定默認0。數組的初始化大小爲10。

可是ArrayList就不能夠進行增量的修改指定。仍是看代碼:

 1 /**
 2      * Increases the capacity to ensure that it can hold at least the
 3      * number of elements specified by the minimum capacity argument.
 4      *
 5      * @param minCapacity the desired minimum capacity
 6      */
 7     private void grow(int minCapacity) {
 8         // overflow-conscious code
 9         int oldCapacity = elementData.length;
10         int newCapacity = oldCapacity + (oldCapacity >> 1);  //看這裏
11         if (newCapacity - minCapacity < 0)
12             newCapacity = minCapacity;
13         if (newCapacity - MAX_ARRAY_SIZE > 0)
14             newCapacity = hugeCapacity(minCapacity);
15         // minCapacity is usually close to size, so this is a win:
16         elementData = Arrays.copyOf(elementData, newCapacity);
17     }

首先在構造函數中,ArrayList就沒有提供相應的設置增量的方法,而擴容方法grow中直接就對數組進行增量50%的操做了,並無相應的參數設置或判斷增量的大小。

在上邊都提到了一個靜態常量是private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

這個常量是數組擴容的最大長度,可是爲何-8呢我看了上邊的描述,感受應該是:

Some VMs reserve some header words in an array.

有些虛擬機會在數組頭部加入一些信息,若是仍是設置最大的話,可能會致使OOM

這就是Vector和ArrayList在擴容及成員變量方面的區別及聯繫了。

接下來咱們看看他們的源碼中插入、刪除等方法爲何說和LinkedList相比要慢

先看代碼:

 
1
public synchronized void insertElementAt(E obj, int index) { 2 modCount++; 3 if (index > elementCount) { 4 throw new ArrayIndexOutOfBoundsException(index 5 + " > " + elementCount); 6 } 7 ensureCapacityHelper(elementCount + 1); 8 System.arraycopy(elementData, index, elementData, index + 1, elementCount - index); 9 elementData[index] = obj; 10 elementCount++; 11 }

Vector集合在add(int index, E element)時實際上調用了insertElementAt方法,他和刪除方法實際上都是對數組進行了copy,因此在大數據量時可能會致使效率下降。ArrayList也是這樣的狀況。

可是在增長調用add(E e)方法時,其實就是在數組中追加數據了,若是追加數據的長度大於實際數組長度的話,會進入到grow擴容方法進行擴容。

Vector和ArrayList都提供了trimToSize()方法,這個方法是對數組容量進行縮減的方法。在這個方法中,調用方法時會對數組的元素容量及數組自己長度進行判斷,若是數組內實際元素的個數比數組自己的長度少的話,調用這個方法會將數組縮減到元素個數大小。在數據量大的時候能夠考慮這樣作,這樣能夠節省沒必要要的空間浪費。看代碼:

1 public void trimToSize() {
2         modCount++;
3         if (size < elementData.length) {
4             elementData = Arrays.copyOf(elementData, size);
5         }
6     }

Vector自己提供了一個同步方法叫setSize方法,該方法能夠對當前集合進行長度設置。若是設置的長度比當前元素個數要大的話會進行判斷是否須要擴容,若是不是,在給定的Size值外的元素將被置爲空值。

看代碼:

 1 public synchronized void setSize(int newSize) {
 2         modCount++;
 3         if (newSize > elementCount) {
 4             ensureCapacityHelper(newSize);
 5         } else {
 6             for (int i = newSize ; i < elementCount ; i++) {
 7                 elementData[i] = null;
 8             }
 9         }
10         elementCount = newSize;
11     }

這大致上就是Vector和ArrayList的區別

 

ps:以上只是我的理解,若有不對請指正。

相關文章
相關標籤/搜索