在上一篇介紹了Java 集合之ArrayList主要講解了ArrayList的一些方法和具體實現,ArrayList是基於數組來實現,當插入新元素時,其後面的元素的位置都須要移動,這顯而易見是個影響性能的操做,數據量一大,再頻繁的執行插入操做那...照例咱們先看集合的結構圖 node
LinkedList和ArrayList 同屬於List接口的,看下詳細的結構圖實現類,那麼二者的方法應該大體相同 數組
AbstractSequentialList類是 AbstractList的一個子類,提供了一個基本的list接口實現,爲了順序訪問的數據存儲結構(鏈表)提供了最小化的實現。AbstractSequentiaList是在迭代器基礎上實現的get、set、add等方法。bash
Deque接口繼承Queue接口,兩端都容許插入和刪除元素,即雙向隊列。源碼分析
實現了Cloneable,能被克隆,實現了Serializable,支持序列化post
咱們查看下LinkedList類中的方法性能
順便附上AbstractSequentiaList抽象類方法 經過查看源碼發現AbstractSequentiaList是在迭代器基礎上實現的get、set、add等方法,而這個迭代是在子類去實現public abstract ListIterator<E> listIterator(int index);
複製代碼
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
複製代碼
Node是個內部類ui
private static class Node<E> {
E item; //結點的值
Node<E> next; //結點的後向指針
Node<E> prev; //結點的前向指針
//構造方法中已完成Node成員的賦值
Node(Node<E> prev, E element, Node<E> next) {
this.item = element; //結點的值賦值爲element
this.next = next; //後向指針賦值
this.prev = prev; //前向指針賦值
}
}
複製代碼
public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
複製代碼
空構造方法構造了一個空的List 其中size爲0 first和last都爲null ,沒有任何元素 LinkedList(Collection<? extends E> c)構造一個包含指定Collection中全部元素的列表 該方法先調用空構造器 而後addAll()把Collection中全部元素添加進去this
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);//檢查是否越界
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
Node<E> pred, succ;
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index);
pred = succ.prev;
}
for (Object o : a) {////for循環結束後,a裏面的元素都添加到當前鏈表裏面,後向添加
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
複製代碼
此方法較長 主要操做就是檢查index是否越界 將collection轉化成數組 循環數組將數組裏面的元素建立爲節點 並按照順序連起來 修改當前節點個數sizespa
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
複製代碼
add 方法直接調用了 linkLast 方法,而 linkLast 方法是不對外開放的。該方法作了三件事情,新增一個節點,改變其先後引用,將 size 和 modCount 自增 1。其中 modCount 是記錄對集合操做的次數。指針
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
複製代碼
檢查下標是否越界,而後調用 unlink 釋放節點。 還有其餘方法這裏就不一一列舉了
結合源碼咱們大體能夠知道LinkedList裏維持了一個鏈表 每一個鏈表單元是一個Node Node的prev指向前一個節點 next指向後一個節點 這樣全部節點都串了起來 如圖
有幾點須要注意的是若常常查找又不多插入和刪除 則推薦使用ArrayList 相反常常插入與刪除 不多查找 則推薦使用LinkedList 平常開發中,固然是ArrayList的使用頻率更高些。下一篇準備講解下Set系列...