在Java中,集合是咱們常常要使用的內容,而且集合也是面試的考點之一,掌握集合幫助咱們瞭解更多的內部構造。面試
list集合是表明的是一個元素有序的,可重複的集合。數組
雖然List中有不少子類的實現,但咱們常常用的仍是那幾個,ArrayList,LinkedList,Vector等內容。安全
ArrayList 是底層由數組構成的集合,可是ArrayList有哪些優勢呢?bash
缺點多線程
// 默認的List 集合大小,在建立ArrayList 的時候沒有制定大小 默認是10
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;
// 數組最大的長度
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
// 改變list 大小的次數,進行增刪除數據都涉及到此數值
protected transient int modCount = 0;
複製代碼
既然是數組集合,就須要涉及到數組的擴容與縮容,在原先咱們學習數組的時候就瞭解,數組的擴容與縮容都涉及到數組內的數據的遷移問題。性能
既然ArrayList 底層是數組,想固然的也須要涉及到這部份內容。學習
add 方法中涉及到增長單個元素,增長單個元素到指定位置,增長一個集合元素,增長一個集合元素到指定位置四個不一樣類型的方法,可是基本內容是相同的.ui
public boolean add(E e) {
元素增長 ,在如今的大小上增長1
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
// 計算是否須要進行擴容 ,須要就進行擴容
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
// 默認的空對象 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
// 判斷 如今list 列表中的元素 是不是空對象。 空對象 返回 最大的值 。不是空對象 返回minCapacity
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
// 擴容結構進行加1
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);
// 若果擴容後的值仍是存放不下 那麼庫容結果直接是 最小的要求容量
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);
}
// 計算容量 選擇
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
複製代碼
從以上代碼來看庫容有如下流程來判斷this
以上內容新建後的流程,有內容後,就涉及到擴容的問題。spa
public void add(int index, E element) {
// 指定位置增長數據,須要檢查該位置是否已經被安置數據若是沒有那麼執行失敗
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
// 進行數據的copy 工做,將該位置的數據日後面進行復制
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
而後修改該值
elementData[index] = element;
size++;
}
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
int numMoved = size - index;
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
複製代碼
整體添加流程簡單來講是這樣的:
ArrayList 集合容量擴容會致使性能問題,Java中複製是須要消耗內容空間,建立一樣數量的對象大小,特別是大批量數據進行庫容容易致使性能降低。
set get 方法沒有須要多說的,根據下標進行數據的讀取與插入,小標註意不要超過集合大小。
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);
//最後的一位置位null 讓gc來處理
elementData[--size] = null; // clear to let GC do its work
返回移除內容
return oldValue;
}
複製代碼
// 批量進行刪除
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
for (; r < size; r++)
// 判斷不被 刪除的元素是否在集合中 集合是 0 1 2 3 4 5 刪除 1 3 complement = true
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws. 1 3 2 3 4 5 異常執行復制copy 這裏主要是存在可能刪除的元素不在集合中
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
if (w != size) {
// clear to let GC do its work 0 1 size = 6 w = 2
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
複製代碼
刪除代碼中主要涉及到