ArrayList:
結構:數組
創建時:1.無參數初始化
2.指定大小初始化
3.指定初始數據初始化
擴容: 1.第一次add時,如果是空數組,將capacity初始化爲10
2.add時超過當前容量,則擴容至當前容量的1.5倍
3.如果擴容1.5倍後不夠,則直接擴容到指定的容量(原始容量+新增的元素數量)
4.如果所需容量大於Integer.MAX_VALUE - 8,則直接擴容到Integer.MAX_VALUE
擴容的本質 是調用System.arraycopy,是複製原數組到一個新的數組,因此非常消耗性能
刪除:
1.刪掉指定位置的元素:先拿到指定位置的元素的值,然後將後面所有元素整體前移一位,最後一位置null(方便gc),size--
2.刪除指定元素時分兩種情況,是null則找null,非null則找equeals的
新增: 允許add null
迭代器: 在用for進行循環時,是不能進行使用原list進行remove的,因爲索引的值一直在變,每remove一個,後面的元素向前移一位.
因此如果要循環刪除list中的元素,要使用Iterator
核心擴容代碼
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果擴容後的值 < 我們的期望值,擴容後的值就等於我們的期望值
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果擴容後的值 > jvm 所能分配的數組的最大值,那麼就用 Integer 的最大值
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 通過複製進行擴容,因此非常消耗性能
elementData = Arrays.copyOf(elementData, newCapacity);
}
LinkedList:
結構:雙向鏈表結構
新增:只能從頭部或尾部新增
刪除:只能從頭部或尾部刪除
查詢:根據索引來查詢節點,查找時採用二分法
迭代器: 迭代器不同於其他迭代器,因爲它是雙向的,因此有它自身的ListIterator,可向前或向後迭代
迭代器的刪除:,刪除之前迭代器迭代到的值,無論之前是向前還是向後迭代,都在同一個方法中進行刪除操作
迭代器初始化時,索引是0,也就是next指向第一個元素
最開始的時候只能next,不能previous
用previous的時候,返回的是上一次next指向的元素
如果使用next之前有previous的操作,那麼這次next指向的是上一次previous返回的元素
核心代碼{
迭代previous: lastReturn=next=(next==null?last:next.prev)//如果next爲null,那麼就是最後一個了,直接等於last
next : lastReturn=next;
next=next.next;
我覺得的linkedlist的重點
public void remove() {
checkForComodification();
// lastReturned 是本次迭代需要刪除的值,分以下空和非空兩種情況:
// lastReturned 爲空,說明調用者沒有主動執行過 next() 或者 previos(),直接報錯
// lastReturned 不爲空,是在上次執行 next() 或者 previos()方法時賦的值
if (lastReturned == null)
throw new IllegalStateException();
Node<E> lastNext = lastReturned.next;
//刪除當前節點
unlink(lastReturned);
//因爲在previous方法中,最後是將next=lastReturned的
if (next == lastReturned)
//如果之前執行的是previous,那麼將刪掉的next記錄起來,下次直接取它的previous
next = lastNext;
else
nextIndex--;
lastReturned = null;
expectedModCount++;
}
ArrayList和LinkedList的主要區別有兩點:
1.ArrayList的大小是受限制的,最大容量是Integer.MAX_VALUE,而LinkedList因爲是雙向聯表結構,因此它在理論上是可以無限大的
2.迭代器不一樣,linkedlist有它特殊的雙向迭代器