ArrayList
其內部使用Object[]數組來存儲,默認長度爲10,一次增長爲原長度的1.5倍,當1.5倍超過int的最大值時爲int的最大值,再大一點就報錯OOM
ArrayList在add元素時,先檢測容量是否夠add,不夠就擴容1.5倍,然後將元素加入數組中,長度+1,這裏爲做多線程的併發處理,在多線程進行添加時,可能出現一起擴容,或同時將元素加到一個位置上,導致異常或數據丟失.
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 判斷容量夠不夠用,不夠就擴容
elementData[size++] = e;//添加元素,長度加一
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//是不是空數組
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);//是不是比原始的10要小
}
ensureExplicitCapacity(minCapacity);//擴容
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)//需要擴容
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);//這裏的oldCapacity >> 1就是原長度除以2,即擴容爲原來長度的1.5倍
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);//檢查是否大於最大值,這裏可能會拋出oom
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);//將數組複製到新的數組中
}
CopyOnWriteArrayList
寫時複製,在add數據時,會有加鎖處理,再進行先複製原數組,在對新數組進行添加操作,最後在指向新數組,以此保證最終的一致性,但其不能保證數據讀取的實時性,因爲在寫入時需要更多的時間了.
public boolean add(E e) {
synchronized (lock) {//加鎖,此處有些版本使用ReentrantLock鎖
Object[] elements = getArray();//獲取原數組
int len = elements.length;//原數組長度
Object[] newElements = Arrays.copyOf(elements, len + 1);//複製原數組且長度+1
newElements[len] = e;//新數組加入元素
setArray(newElements);//指向新的數組,即替換原數組
return true;
}
}
由此可見,寫時複製列表的數組擴容每次擴容長度爲+1,使用鎖的機制來保證同一時刻只有一個在寫,從而保證數組最終的一致性,且能保證在寫的時候,原數據依然可以讀取,但其讀取的是舊數據.
當然由於複製數組,會造成更多的內存佔用,可能導致gc頻繁會gc時間較長,所以使用與讀多寫少的地方
Vector
向量列表,與ArrayList類似,在初始化的時候可設置其初始大小,默認爲10,但每次擴容的長度可在初始化時設置,若不設置,默認增長爲原數組的兩倍.除此之外,Vector中的方法都進行了同步操作,一次解決多線程的併發問題,但由於都進行了同步,所以效率會比其他的列表低.
public synchronized boolean add(E var1) {//整個方法都同步
++this.modCount;
this.ensureCapacityHelper(this.elementCount + 1);//擴容判斷
this.elementData[this.elementCount++] = var1;//存入元素
return true;
}
public synchronized E get(int var1) {//讀的時候也是整個方法都同步
if(var1 >= this.elementCount) {//越界直接拋異常
throw new ArrayIndexOutOfBoundsException(var1);
} else {
return this.elementData(var1);
}
}
Stack
繼承與Vector的棧,其中的方法也是同步的,符合棧數據結構的先進後出,使用push()入棧,pop()出棧,peek()獲取棧頂元素但不出棧,search()搜索對應數據在棧中的位置,empty()判斷是否0元素
IdentityStack
與Stack一樣,但其不同之處在於相等的判斷,Stack相等的判斷使用equls(),而IdentityStack使用==,即IdentityStack爲對象相等,Stack爲值相等
IdentityStack中爲:
public synchronized int indexOf(Object o, int pos) {
for (int i = pos; i < size(); i++) {
if (get(i) == o) {//對象相等
return i;
}
}
return -1;
}
Stack中的判斷使用了Voter的判斷,爲
public synchronized int lastIndexOf(Object o, int index) {
if (index >= elementCount)
throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
if (o == null) {
for (int i = index; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = index; i >= 0; i--)
if (o.equals(elementData[i]))//值相等
return i;
}
return -1;
}
LinkedList
鏈表結構的列表, 其中特有的方法:addFirst(E e) ,addLast(E e) ,getFirst() ,getLast() ,removeFirst(),removeLast()
還提供了棧結構的實現與隊列結構的實現
棧:先進後出push() ,pop()
隊列:先進先出offer(),poll()
其插入刪除速度會比數組的快很多,其中沒有做併發處理
小結
java提供了不同的list,開發者需要根據應用場景來選擇合適的list,雖然有些可能寫錯了,希望大家指出糾正