在上篇文章Java集合(三) ArrayList詳解的學習和源碼分析中,咱們知道ArrayList是以數組實現,它的優點是查詢性能高,劣勢是按順序增刪性能差。若是在不肯定元素數量的狀況時,不建議使用ArrayList。其實當這種狀況時,咱們就可使用LinkedList了。java
一直以來咱們用快慢來描述存儲算法,這種直觀的描述是很差的。有一種方法能夠量化一種操做的耗時狀況。咱們能夠借用數學分析中的大O記號來描述這種關係。
解決一個規模爲n的問題所花費的步驟若是是n的常數倍,咱們就記這個方法的複雜度爲O(n)。例如,給一個數組,求這個數組中的最大值,須要遍歷這個數組,若是數組長度爲n,那麼遍歷數組的步驟就是n。因此,這是一種O(n)的操做。一樣,解決一個規模爲n的問題所花費的步驟若是是n^2的常數倍,咱們就記這個方法的複雜度爲O(n^2)。好比冒泡排序。而解決問題的步驟若是與問題規模無關,這個時間複雜度就是O(1)的。好比,數組的隨機存取。而數組的順序存儲就是O(n)的。node
在學習LinkedList以前,咱們先對數據結構中鏈表作一個簡單的回顧。鏈表是一種物理存儲單元上非連續、非順序的存儲結構,數據元素的邏輯順序是經過鏈表中的指針連接次序實現的。鏈表由一系列結點(鏈表中每個元素成爲結點)組成,結點能夠在運行時動態生成。
能夠這樣理解:
有一條街,小明住在街中一角,他有小紅的地址,而後小紅也是住在這條街,他有小花的地址,一樣小花也有別人的地址。某天我想找小紅玩,可是我不知道她住在哪裏,我能夠問小明,就知道小紅住在哪裏了。那麼小明小紅小花這些人之間的關係就組成一個鏈表。 git
public class LinkNode {
public int data;
public LinkNode next;
public LinkNode(int data) {
this.data = data;
this.next = null;
}
}
複製代碼
咱們定義了一個LinkNode類,這個類有兩個成員變量,一個是整形data,還有一個是指向LinkNode類型的引用。經過這個引用,就能夠把多個LinkNode串起來,好比,下面的代碼:github
LinkNode head = new LinkNode(1);
head.next = new LinkNode(2);
複製代碼
這樣就在內存裏建立了兩個LinkNode對象,它們之間的關係就像這樣: 算法
head所引用的那個LinkNode,其data爲1,其next指向下一個LinkNode,其data爲2,next域爲空。若是我想在head以後,增長一個鏈表項,讓這個鏈表變成下圖的樣子,該怎麼作? 數組
思路就是先把新的結點的next設爲head的next,而後再使得head.next指向新的結點便可。LinkNode newNode = new LinkNode(3);
newNode.next = head.next;
head.next = newNode;
複製代碼
反過來,想要把head後面的那個結點刪掉,也很簡單,只須要讓head的next再日後指一項,把原來head後面的那一項跳過去就能夠了:安全
head.next = head.next.next;
複製代碼
能夠看到,在鏈表中,指定的結點後面添加一個項是常數時間的,也就是O(1),刪除一個項也是同樣的。但與數組不一樣的,若是我要完成「查詢鏈表中的第n項是什麼」這個操做,就會變成O(n)的,由於咱們每次查找都必須從頭開始,依次向後查找。bash
public static int queryData(LinkNode head, int index) {
LinkNode cur = head;
for (int i = 0; i < index; i++) {
cur = cur.next;
}
return cur.data;
}
複製代碼
再看一個問題,假如我知道了一個LinkNode,不妨記爲temp,位於一個鏈表中,若是想知道這個結點的上一個結點是什麼,應該怎麼辦?對於咱們前邊定義的鏈表結構,只能從頭開始找,去判斷是否有某個結點,它的next與temp相等。若是相等就說明,這個結點就是temp的前序結點。代碼以下:數據結構
public static LinkNode findPrevious(LinkNode head, LinkNode temp) {
LinkNode cur = head;
while (cur != null) {
if (cur.next == temp)
return cur;
cur = cur.next;
}
return null;
}
複製代碼
實際上,在工程實踐中,使用鏈表的時候,常常會有「查詢某個結點的前一結點」這樣的需求,爲了加速這一過程,咱們其實能夠修改一下LinkNode的定義,結它加上一個指向前序結點的成員變量:ide
public class DoubleLinkNode {
public int data;
public LinkNode next;
public LinkNode prev;
public DoubleLinkNode(int data) {
this.data = data;
this.next = null;
this.prev = null;
}
}
複製代碼
這樣的話,鏈表就成了這個樣子了:
這樣一來,查找某個結點的上一個結點,只要返回它的prev就能夠了。 LinkedList以雙向鏈表實現。鏈表無容量限制,但雙向鏈表自己使用了更多空間,也須要額外的鏈表指針操做。除了實現List接口外,LinkedList還爲在列表的開頭及結尾get、remove和insert元素提供了統一的命名方法。這些操做能夠將連接列表看成棧,隊列和雙端隊列來使用。
按索引訪問元素:get(i)/set(i,e)要很是噁心的遍歷鏈表將指針移動到位(若是i > 數組大小的一半,會從末尾開始移動)。插入、刪除元素時修改先後節點的指針便可,但仍是要遍歷部分鏈表的指針才能移動到下標所指的位置,只有在鏈表兩頭的操做:add(),addFirst(),removeLast()或用iterator()上的remove()能省掉指針的移動。
LinkedList一樣是非線程安全的,只在單線程下適合使用。若是多個線程同時訪問一個連接列表,而其中至少一個線程從結構上修改了該列表,則它必須保持外部同步。(結構修改指添加或刪除一個或多個元素的任何操做;僅設置元素的值不是結構修改。)這通常經過對天然封裝該列表的對象進行同步操做來完成。若是不存在這樣的對象,則應該使用 Collections.synchronizedList 方法來「包裝」該列表。
LinkedList的iterator和listIterator方法返回的迭代器是快速失敗的(fail-fast機制):在迭代器建立以後,若是從結構上對列表進行修改,除非經過迭代器自身的remove或add方法,其餘任什麼時候間任何方式的修改,迭代器都將拋出 ConcurrentModificationException。
LinkedList實現了Serializable接口,所以它支持序列化,可以經過序列化傳輸,實現了Cloneable接口,能被克隆。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable,
java.io.Serializable {
//LinkedList中鏈表元素個數
transient int size = 0;
//鏈表頭結點
transient Node<E> first;
//鏈表尾結點
transient Node<E> last;
//默認構造方法,生成一個空的鏈表
public LinkedList() {
}
//根據c裏面的元素生成一個LinkedList
public LinkedList(Collection<? extends E> c) {
//調用空的構造方法
this();
//將c裏面的元素添加到空鏈表尾部
addAll(c);
}
//首部增長結點,結點的值爲e
private void linkFirst(E e) {
final Node<E> f = first;//f指向頭結點
//生成一個新結點,結點的值爲e,其前向指針爲null,後向指針爲f
final Node<E> newNode = new Node<>(null, e, f);
//first指向新生成的結點,f保存着舊的頭結點信息
first = newNode;
if (f == null)
//若是f爲null,則表示整個鏈表目前是空的,則尾結點也指向新結點
last = newNode;
else
//f(老的頭結點)的前向指向最新的結點信息
f.prev = newNode;
size++;//元素個數+1
modCount++;//修改次數+1
}
//尾部增長結點,結點的值爲e
void linkLast(E e) {
final Node<E> l = last; //l指向尾結點
//生成一個新結點,結點的值爲e,其前向指針爲l,後向指針爲null
final Node<E> newNode = new Node<>(l, e, null);
//last指向新生成的結點,l保存着舊的尾結點信息
last = newNode;
if (l == null)
//若是l爲null,則表示整個鏈表目前是空的,則頭結點也指向新結點
first = newNode;
else
//l(舊的尾結點)的後向指針指向最新的結點信息
l.next = newNode;
size++;//元素個數+1
modCount++;//修改次數+1
}
//非空結點succ以前插入新結點,新結點的值爲e
void linkBefore(E e, Node<E> succ) {
// assert succ != null; //外界調用需保證succ不爲null,不然程序會拋出空指針異常
final Node<E> pred = succ.prev;//pred指向succ的前向結點
//生成一個新結點,結點的值爲e,其前向指針指向pred,後向指針指向succ
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;//succ的前向指針指向newNode
if (pred == null)
//若是pred爲null,則表示succ爲頭結點,此時頭結點指向最新生成的結點newNode
first = newNode;
else
//pred的後向指針指向新生成的結點,此時已經完成告終點的插入操做
pred.next = newNode;
size++;//元素個數+1
modCount++;//修改次數+1
}
//刪除頭結點,並返回該結點的值
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;//需確保f爲頭結點,且鏈表不爲null
final E element = f.item;//得到結點的值
final Node<E> next = f.next;//next指向f的後向結點
f.item = null;//釋放數據結點
f.next = null; // help GC //釋放f的後向指針
first = next; //first指向f的後向結點
if (next == null)
//若是next爲null,則表示f爲last結點,此時鏈表即爲空鏈表
last = null;
else
//修改next的前向指針,由於first結點的前向指針爲null
next.prev = null;
size--; //元素個數-1
modCount++; //修改次數+1
return element;
}
//刪除尾結點,並返回尾結點的內容
private E unlinkLast(Node<E> l) {
// assert l == last && l != null; //需確保l爲尾結點,且鏈表不爲null
final E element = l.item; //得到結點的值
final Node<E> prev = l.prev; //prev執行1的前向結點
l.item = null; //釋放l結點的值
l.prev = null; // help GC //釋放l結點的前向指針
last = prev; //last結點指向l的前向結點
if (prev == null)
//若是prev爲null,則表示l爲first結點,此時鏈表即爲空鏈表
first = null;
else
//修改prev的後向指針,由於last結點的後向指針爲null
prev.next = null;
size--;//元素個數-1
modCount++;//修改次數+1
return element;
}
//刪除結點x
E unlink(Node<E> x) {
// assert x != null; //需確保x不爲null,不然後續操做會拋出空指針異常
final E element = x.item; //保存x結點的值
final Node<E> next = x.next;//next指向x的後向結點
final Node<E> prev = x.prev;//prev指向x的前向結點
if (prev == null) {
//若是prev爲空,則x結點爲first結點,此時first結點指向next結點(x的後向結點)
first = next;
} else {
prev.next = next;//x的前向結點的後向指針指向x的後向結點
x.prev = null; //釋放x的前向指針
}
if (next == null) {
//若是next結點爲空,則x結點爲尾部結點,此時last結點指向prev結點(x的前向結點)
last = prev;
} else {
next.prev = prev;//x的後向結點的前向指針指向x的前向結點
x.next = null; //釋放x的後向指針
}
x.item = null; //釋放x的值節點,此時x節點能夠徹底被GC回收
size--; //元素個數-1
modCount++; //修改次數+1
return element;
}
//得到頭結點的值
public E getFirst() {
final Node<E> f = first;//f指向first結點
if (f == null)//若是鏈表爲空
throw new NoSuchElementException();
return f.item;//返回first結點的值
}
//得到尾結點的值
public E getLast() {
final Node<E> l = last; //l指向last結點
if (l == null)//若是鏈表爲空
throw new NoSuchElementException();
return l.item;//返回last結點的值
}
//移除頭結點
public E removeFirst() {
final Node<E> f = first;//得到頭結點
if (f == null)//若是鏈表爲空
throw new NoSuchElementException();
return unlinkFirst(f); //摘除頭結點
}
//移除尾結點
public E removeLast() {
final Node<E> l = last;//得到尾結點
if (l == null)//若是鏈表爲空
throw new NoSuchElementException();
return unlinkLast(l);//摘除尾結點
}
//添加到頭結點,結點的值爲e
public void addFirst(E e) {
linkFirst(e);//添加到頭部
}
//添加到尾結點
public void addLast(E e) {
linkLast(e);//添加到尾部
}
//判斷元素(值爲o)是否o在鏈表中
public boolean contains(Object o) {
return indexOf(o) != -1;//定位元素
}
//返回元素個數
public int size() {
return size;
}
//添加元素,元素值爲e
public boolean add(E e) {
linkLast(e);//添加到鏈表尾部
return true;
}
//移除值爲o的元素,o能夠爲null,找到一個刪除即返回
public boolean remove(Object o) {
if (o == null) {//元素爲null
for (Node<E> x = first; x != null; x = x.next) {//從結點開始遍歷
if (x.item == null) {//找到一個結點
unlink(x); //刪除元素
return true;
}
}
} else {//元素不爲空
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
//將c中的元素都添加到當前鏈表中
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);//添加到鏈表尾部
}
//在序號爲index處,添加c中全部的元素到當前鏈表中(後向添加)
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);//判斷index是否超出界
Object[] a = c.toArray();//將集合轉換爲數組
int numNew = a.length;
if (numNew == 0)
return false;
Node<E> pred, succ;
if (index == size) {//若是index爲元素個數,即index個結點爲尾結點
succ = null;
pred = last;//指向爲結點
} else {
succ = node(index); //succ指向第index個結點
pred = succ.prev; //pred指向succ的前向結點
}
//for循環結束後,a裏面的元素都添加到當前鏈表裏面,後向添加
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
//新生成一個結點,結點的前向指針指向pred,後向指針爲null
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
//若是pred爲null,則succ爲當前頭結點
first = newNode;
else
//pred的後向指針指向新結點
pred.next = newNode;
pred = newNode;//pred移動到新結點
}
if (succ == null) {
last = pred;//succ爲null,這表示index爲尾結點以後
} else {
//pred表示全部元素添加以後的最後結點,此時pred的後向指針指向以前的記錄的結點
pred.next = succ;
succ.prev = pred;//以前記錄的結點指向添加元素以後的最後結點
}
size += numNew;//元素個數+num
modCount++;//修改次數+1
return true;
}
//清除鏈表裏面的全部元素
public void clear() {
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null; //釋放值結點,便於GC回收
x.next = null; //釋放前向指針
x.prev = null; //釋放後向指針
x = next; //後向遍歷
}
first = last = null;//釋放頭尾結點
size = 0;
modCount++;
}
//得到第index個結點的值
public E get(int index) {
checkElementIndex(index);
return node(index).item; //點位第index結點,返回值信息
}
//設置第index元素的值
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(index);//定位第index個結點
E oldVal = x.item;
x.item = element;
return oldVal;
}
//第index個結點以前添加結點
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
//刪除第index個結點
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
//判斷index是不是鏈表中的元素的索引
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
//判斷index是不是鏈表中的元素的索引
private boolean isPositionIndex(int index) {
return index >= 0 && index <= size;
}
private String outOfBoundsMsg(int index) {
return "Index: " + index + ", Size: " + size;
}
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private void checkPositionIndex(int index) {
if (!isPositionIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
//定位鏈表中的第index個結點
Node<E> node(int index) {
// assert isElementIndex(index);//確保是合法的索引,即0<=index<=size
//index小於size的一半時,從頭向後找
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {//index大於size的一半時,從尾向前找
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
//定位元素,首次出現的元素的值爲o的結點序號
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1;
}
//定位元素,最後一次出現的元素值爲o的元素序號
public int lastIndexOf(Object o) {
int index = size;
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (x.item == null)
return index;
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
index--;
if (o.equals(x.item))
return index;
}
}
return -1;
}
//實現隊列操做,返回第一個元素的值
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
//實現隊列操做,返回第一個結點
public E element() {
return getFirst();
}
//實現隊列操做,彈出第一個結點
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
//刪除結點
public E remove() {
return removeFirst();
}
//添加結點
public boolean offer(E e) {
return add(e);
}
//添加頭結點
public boolean offerFirst(E e) {
addFirst(e);
return true;
}
//添加尾結點
public boolean offerLast(E e) {
addLast(e);
return true;
}
//返回頭結點的值
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
//返回尾結點的值
public E peekLast() {
final Node<E> l = last;
return (l == null) ? null : l.item;
}
//彈出第一個結點
public E pollFirst() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
//彈出最後一個結點
public E pollLast() {
final Node<E> l = last;
return (l == null) ? null : unlinkLast(l);
}
//添加頭部結點
public void push(E e) {
addFirst(e);
}
//彈出第一個結點
public E pop() {
return removeFirst();
}
//刪除值爲o的結點
public boolean removeFirstOccurrence(Object o) {
return remove(o);
}
//刪除值爲o的結點(從尾部遍歷)
public boolean removeLastOccurrence(Object o) {
if (o == null) {
for (Node<E> x = last; x != null; x = x.prev) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node<E> x = last; x != null; x = x.prev) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
//返回雙向迭代器
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
}
//私有內部類,實現雙向迭代器
private class ListItr implements ListIterator<E> {
private Node<E> lastReturned;//記錄當前結點信息
private Node<E> next;//當前結點的後向結點
private int nextIndex;//當前結點的序號
private int expectedModCount = modCount;//修改次數
//初始化
ListItr(int index) {
// assert isPositionIndex(index);
next = (index == size) ? null : node(index);
nextIndex = index;
}
//是否有結點
public boolean hasNext() {
return nextIndex < size;
}
//返回下一個結點
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next;//記錄當前結點
next = next.next;//向後移動
nextIndex++;//結點序號+1
return lastReturned.item;
}
//是否有前向結點
public boolean hasPrevious() {
return nextIndex > 0;
}
//返回前向結點
public E previous() {
checkForComodification();
if (!hasPrevious())
throw new NoSuchElementException();
lastReturned = next = (next == null) ? last : next.prev;
nextIndex--;
return lastReturned.item;
}
//返回當前結點序號
public int nextIndex() {
return nextIndex;
}
//返回當前結點的前一個序號
public int previousIndex() {
return nextIndex - 1;
}
//刪除結點
public void remove() {
checkForComodification();
if (lastReturned == null)
throw new IllegalStateException();
Node<E> lastNext = lastReturned.next;
unlink(lastReturned);
if (next == lastReturned)
next = lastNext;
else
nextIndex--;
lastReturned = null;
expectedModCount++;
}
//設置當前結點的值
public void set(E e) {
if (lastReturned == null)
throw new IllegalStateException();
checkForComodification();
lastReturned.item = e;
}
//當前結點前面插入新結點信息
public void add(E e) {
checkForComodification();
lastReturned = null;
if (next == null)
linkLast(e);
else
linkBefore(e, next);
nextIndex++;
expectedModCount++;
}
// Lambda表達式結合迭代器進行遍歷
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (modCount == expectedModCount && nextIndex < size) {
action.accept(next.item);
lastReturned = next;
next = next.next;
nextIndex++;
}
checkForComodification();
}
//判斷迭代期間是否被修改
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
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 Iterator<E> descendingIterator() {
return new DescendingIterator();
}
//前向迭代器
private class DescendingIterator implements Iterator<E> {
private final ListItr itr = new ListItr(size());
public boolean hasNext() {
return itr.hasPrevious();
}
public E next() {
return itr.previous();
}
public void remove() {
itr.remove();
}
}
@SuppressWarnings("unchecked")
private LinkedList<E> superClone() {
try {
return (LinkedList<E>) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
//拷貝操做,執行淺拷貝,只複製引用,而沒有複製引用指向的內存
public Object clone() {
LinkedList<E> clone = superClone();
// Put clone into "virgin" state
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
// Initialize clone with our elements
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item);
return clone;
}
//轉換爲數組
public Object[] toArray() {
Object[] result = new Object[size];
int i = 0;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
return result;
}
//轉換爲數組
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size)
a = (T[]) java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
int i = 0;
Object[] result = a;
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
if (a.length > size)
a[size] = null;
return a;
}
//序列化版本
private static final long serialVersionUID = 876323262645176354L;
//序列化
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out any hidden serialization magic
s.defaultWriteObject();
// Write out size
s.writeInt(size);
// Write out all elements in the proper order.
for (Node<E> x = first; x != null; x = x.next)
s.writeObject(x.item);
}
//反序列化
@SuppressWarnings("unchecked")
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in any hidden serialization magic
s.defaultReadObject();
// Read in size
int size = s.readInt();
// Read in all elements in the proper order.
for (int i = 0; i < size; i++)
linkLast((E) s.readObject());
}
//獲取一個分割器,1.8新增
@Override
public Spliterator<E> spliterator() {
return new LLSpliterator<E>(this, -1, 0);
}
/**
* A customized variant of Spliterators.IteratorSpliterator
*/
static final class LLSpliterator<E> implements Spliterator<E> {
···
}
}
複製代碼
關於LinkedList的源碼,給出幾點比較重要的總結:
1.從源碼中很明顯能夠看出,LinkedList的實現是基於雙向鏈表的,且頭結點中不存放數據。
2.注意兩個不一樣的構造方法。無參構造方法直接創建一個僅包含head節點的空鏈表;包含Collection的構造方法,先調用無參構造方法創建一個空鏈表,然後將Collection中的數據加入到鏈表的尾部後面。
3.在查找和刪除某元素時,源碼中都劃分爲該元素爲null和不爲null兩種狀況來處理,LinkedList中容許元素爲null。
4.LinkedList是基於鏈表實現的,所以不存在容量不足的問題,因此這裏沒有擴容的方法。
5.Node node(int index)方法。該方法返回雙向鏈表中指定位置處的節點,而鏈表中是沒有下標索引的,要指定位置出的元素,就要遍歷該鏈表,從源碼的實現中,咱們看到這裏有一個加速動做。源碼中先將index與長度size的一半比較,若是index<(size<<1),就只從位置0日後遍歷到位置index處,而若是index>(size<<1),就只從位置size往前遍歷到位置index處。這樣能夠減小一部分沒必要要的遍歷,從而提升必定的效率(實際上效率仍是很低)。
6.LinkedList是基於鏈表實現的,所以插入刪除效率高,查找效率低(雖然有一個加速動做)。
7.要注意源碼中還實現了棧和隊列的操做方法,所以也能夠做爲棧、隊列和雙端隊列來使用。