java集合框架04——LinkedList和原始碼分析
上一章學習了ArrayList,並分析了其原始碼,這一章我們將對LinkedList的具體實現進行詳細的學習。依然遵循上一章的步驟,先對LinkedList有個整體的認識,然後學習它的原始碼,深入剖析LinkedList。
LinkedList簡介
首先看看LinkedList與Collection的關係:
LinkedList的繼承關係如下:
java.lang.Object ↳ java.util.AbstractCollection<E> ↳ java.util.AbstractList<E> ↳ java.util.AbstractSequentialList<E> ↳ java.util.LinkedList<E> public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable {}
LinkedList是一個繼承與AbatractSequentialList的雙向連結串列。它也可以被當作堆疊、佇列或雙端佇列進行操作。
LinkedList實現了List介面,能對它進行佇列操作。
LinkedList實現了Deque介面,即能將LinkedList當作雙端佇列使用。
LinkedList實現了java.io.Serializable介面,這意味著LinkedList支援序列化,能通過序列化去傳輸。
LinkedList是非同步的。
這裡插一句,簡單說一下AbstractSequentialList,因為LinkedList是其子類。
AbstractSequentialList實現了get(int index)、set(int index, E element)、add(int index, E element)和remove(int index)這些方法。這些介面都是隨機訪問List的,LinkedList是雙向連結串列,既然它繼承與AbstractSequentialList,就相當於已經實現了“get(int index)”這些介面,可以支援隨機訪問了。
此外,如果我們需要通過AbstractSequentialList實現一個自己的列表,只需要擴充套件此類,並提供listIterator()和size()方法的實現即可。若要實現不可修改的列表,則需要實現列表迭代器的hashNext、next、hashPrevious、previous和index方法即可。
下面先總覽一下LinkedList的建構函式和API:
LinkedList的API
boolean add(E object)
void add(int location, E object)
boolean addAll(Collection<? extends E> collection)
boolean addAll(int location, Collection<? extends E> collection)
void addFirst(E object)
void addLast(E object)
void clear()
Object clone()
boolean contains(Object object)
Iterator<E> descendingIterator()
E element()
E get(int location)
E getFirst()
E getLast()
int indexOf(Object object)
int lastIndexOf(Object object)
ListIterator<E> listIterator(int location)
boolean offer(E o)
boolean offerFirst(E e)
boolean offerLast(E e)
E peek()
E peekFirst()
E peekLast()
E poll()
E pollFirst()
E pollLast()
E pop()
void push(E e)
E remove()
E remove(int location)
boolean remove(Object object)
E removeFirst()
boolean removeFirstOccurrence(Object o)
E removeLast()
boolean removeLastOccurrence(Object o)
E set(int location, E object)
int size()
<T> T[] toArray(T[] contents)
Object[] toArray()
LinkedList包含三個重要的成員:first、last和size:first是雙向連結串列的表頭,last是雙向連結串列的尾節點,size是雙向連結串列中的節點個數。
LinkedList原始碼分析(基於JDK1.7)
下面通過分析LinkedList的原始碼更加深入的瞭解LinkedList原理。由於LinkedList是通過雙向連結串列實現的,所以原始碼也比較容易理解:package java.util;
/*雙向連結串列*/
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
/**
* 這裡先說一下transient關鍵字的用法:
* 一個物件只要實現了Serilizable介面,這個物件就可以被序列化,java的這種序列化模式為開發者提供了很多便利,可以不必關係具體序列化的過程,
* 只要這個類實現了Serilizable介面,這個的所有屬性和方法都會自動序列化。但是有種情況是有些屬性是不需要序列號的,所以就用到這個關鍵字。
* 只需要實現Serilizable介面,將不需要序列化的屬性前新增關鍵字transient,序列化物件的時候,這個屬性就不會序列化到指定的目的地中。
*/
transient int size = 0; //LinkedList中元素的個數
transient Node<E> first; //連結串列的頭結點
transient Node<E> last; //連結串列的尾節點
public LinkedList() { //預設建構函式,建立一個空連結串列
}
//按照c中的元素生成一個LinkedList
public LinkedList(Collection<? extends E> c) {
this();
addAll(c); //將c中的元素新增到空連結串列的尾部
}
/***************************** 新增頭結點 ********************************/
public void addFirst(E e) {
linkFirst(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 = newNode; //first指向新生成的結點,f儲存著老的頭結點資訊
if (f == null)
last = newNode; //如果f為null,則表示整個連結串列目前是空的,則尾結點也指向新結點
else
f.prev = newNode;
size++;
modCount++; //修改次數+1
}
/****************** 新增尾節點,與上面新增頭結點原理一樣 ******************/
public void addLast(E e) {
linkLast(e);
}
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++;
}
/****************** 在非空節點succ之前插入新節點e ************************/
void linkBefore(E e, Node<E> succ) {
// assert succ != null; //外界呼叫需保證succ不為null,否則程式會丟擲空指標異常
final Node<E> pred = succ.prev;
//生成一個新結點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++;
modCount++;
}
/*********************** 刪除頭結點,並返回頭結點的值 *********************/
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f); //private方法
}
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null; //需確保f為頭結點,且連結串列不為Null
final E element = f.item; //獲得節點的值
final Node<E> next = f.next; //獲得頭結點下一個節點
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
//如果next為null,則表示f為last結點,此時連結串列即為空連結串列
last = null;
else
//修改next的前向指標,因為first結點的前向指標為null
next.prev = null;
size--;
modCount++;
return element;
}
/********************** 刪除尾節點,並返回尾節點的值 ********************/
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l); //private方法
}
private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
/******************** 刪除為空節點x,並返回該節點的值 ******************/
E unlink(Node<E> x) {
// assert x != null; //需確保x不為null,否則後續操作會丟擲空指標異常
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
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--;
modCount++;
return element;
}
/********************** 獲得頭結點的值 ********************/
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
/********************** 獲得尾結點的值 ********************/
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
/*************** 判斷元素(值為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的元素 *************/
public boolean remove(Object o) {
if (o == null) {
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) { //找到即返回
unlink(x);
return true;
}
}
} else {//o不為空
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
/*************** 將集合e中所有元素新增到連結串列中 *************/
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
//從index開始,向後新增的
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index); //判斷index是否越界
Object[] a = c.toArray(); //將集合c轉換為陣列
int numNew = a.length;
if (numNew == 0)
return false;
Node<E> pred, succ;
if (index == size) {//即index個節點在尾節點後面
succ = null;
pred = last; //pred指向尾節點
} else {
succ = node(index); //succ指向第index個節點
pred = succ.prev; //pred指向succ的前向節點
}
//for迴圈結束後,a裡面的元素都新增到當前連結串列裡了,向後新增
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
if (pred == null)
first = newNode; //如果pred為null,則succ為頭結點
else
pred.next = newNode; //pred的後向指標指向新節點
pred = newNode; //pred指向新節點,即往後移動一個節點,用於下一次迴圈
}
if (succ == null) { //succ為null表示index為尾節點之後
last = pred;
} else {
//pred表示所有元素新增好之後的最後那個節點,此時pred的後向指標指向之前記錄的節點,即index處的節點
pred.next = succ;
succ.prev = pred; //之前記錄的結點指向新增元素之後的最後結點
}
size += numNew;
modCount++;
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++;
}
/******************* Positional Access Operations ***********************/
//獲得第index個節點的值
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
//設定第index元素的值
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(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是否為連結串列中的元素下標。。。包含了size
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);
//index<size/2時,從頭開始找
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else { //index>=size/2時,從尾開始找
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
/*************************** Search Operations *************************/
//返回首次出現指定元素值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; //沒有則返回-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;
}
/***************************** Queue operations ***********************/
//下面是與棧和佇列相關的操作了
//實現棧的操作,返回第一個元素的值
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);
}
/************************* Deque operations **********************/
//下面都是和雙端佇列相關的操作了
//新增頭結點
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;
}
/************************* ListIterator ***********************/
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index); //ListItr是一個雙向迭代器
}
//實現雙向迭代器
private class ListItr implements ListIterator<E> {
private Node<E> lastReturned = null;//記錄當前節點資訊
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++;
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
//返回前向迭代器
public Iterator<E> descendingIterator() {
return new DescendingIterator();
}
//通過ListItr.previous來提供前向迭代器,方向與原來相反
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();
}
}
//克隆操作,執行淺拷貝,只複製引用,沒有複製引用指向的記憶體
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;
}
/*************************** toArray ****************************/
//返回LinkedList的Object[]陣列
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;
}
//返回LinkedList的模板陣列,儲存在a中
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size)
//如果a的大小 < LinkedList的元素個數,意味著陣列a不能容納LinkedList的全部元素
//則新建一個T[]陣列,T[]的大小為LinkedList大小,並將T[]賦給a
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
//如果a大小夠容納LinkedList的全部元素
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;
/************************* Serializable **************************/
//java.io.Serializable的寫入函式
//將LinkedList的“容量,所有元素值”寫入到輸出流中
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);
}
//java.io.Serializable的讀取函式:根據寫入方式反向讀出
//先將LinkedList的“容量”讀出,然後將“所有元素值”讀出
@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). LinkedList是通過雙向連結串列去實現的。
2). 從LinkedList的實現方式中可以看出,它不存在容量不足的問題,因為是連結串列。
3). LinkedList實現java.io.Serializable的方式。當寫入到輸出流時,先寫入“容量”,再依次寫出“每一個元素”;當讀出輸入流時,先讀取“容量”,再依次讀取“每一個元素”。
4). LinkdedList的克隆函式,即是將全部元素克隆到一個新的LinkedList中。
5). 由於LinkedList實現了Deque,而Deque介面定義了在雙端佇列兩端訪問元素的方法。提供插入、移除和檢查元素的方法。
6). LinkedList可以作為FIFO(先進先出)的佇列,作為FIFO的佇列時,下標的方法等價:
佇列方法 等效方法
add(e) addLast(e)
offer(e) offerLast(e)
remove() removeFirst()
poll() pollFirst()
element() getFirst()
peek() peekFirst()
7). LinkedList可以作為LIFO(後進先出)的棧,作為LIFO的棧時,下表的方法等價:棧方法 等效方法
push(e) addFirst(e)
pop() removeFirst()
peek() peekFirst()
LinkedList遍歷方式
LinkedList支援多種遍歷方式,建議不要採用隨機訪問的方式去遍歷LinkedList,而採用逐個遍歷的方式。下面我們來看看每種遍歷方式:
1). 通過Iterator迭代器遍歷
for(Iterator iter = list.iterator(); iter.hasNext();)
iter.next();
2). 通過快速隨機訪問遍歷int size = list.size();
for (int i=0; i<size; i++) {
list.get(i);
}
3). 通過for迴圈遍歷for (Integer integ:list)
;
4). 通過pollFirst()或pollLast()來遍歷while(list.pollFirst() != null)
;
while(list.pollLast() != null)
;
5). 通過removeFirst()或removeLast()來遍歷while(list.removeFirst() != null)
;
while(list.removeLast() != null)
;
下面通過一個測試用例來測試一下這些方法的效率:import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;
/*
* @description 測試LinkedList的幾種遍歷方式和效率
* @author eson_15
*/
public class LinkedListThruTest {
public static void main(String[] args) {
// 通過Iterator遍歷LinkedList
iteratorLinkedListThruIterator(getLinkedList()) ;
// 通過快速隨機訪問遍歷LinkedList
iteratorLinkedListThruForeach(getLinkedList()) ;
// 通過for迴圈的變種來訪問遍歷LinkedList
iteratorThroughFor2(getLinkedList()) ;
// 通過PollFirst()遍歷LinkedList
iteratorThroughPollFirst(getLinkedList()) ;
// 通過PollLast()遍歷LinkedList
iteratorThroughPollLast(getLinkedList()) ;
// 通過removeFirst()遍歷LinkedList
iteratorThroughRemoveFirst(getLinkedList()) ;
// 通過removeLast()遍歷LinkedList
iteratorThroughRemoveLast(getLinkedList()) ;
}
private static LinkedList<Integer> getLinkedList() {
LinkedList<Integer> llist = new LinkedList<Integer>();
for (int i=0; i<500000; i++)
llist.addLast(i);
return llist;
}
/**
* 通過快迭代器遍歷LinkedList
*/
private static void iteratorLinkedListThruIterator(LinkedList<Integer> list) {
if (list == null)
return ;
long start = System.currentTimeMillis();
for(Iterator<Integer> iter = list.iterator(); iter.hasNext();)
iter.next();
long end = System.currentTimeMillis();
long interval = end - start;
System.out.println("iteratorLinkedListThruIterator:" + interval+" ms");
}
/**
* 通過快速隨機訪問遍歷LinkedList
*/
private static void iteratorLinkedListThruForeach(LinkedList<Integer> list) {
if (list == null)
return ;
long start = System.currentTimeMillis();
int size = list.size();
for (int i=0; i<size; i++) {
list.get(i);
}
long end = System.currentTimeMillis();
long interval = end - start;
System.out.println("iteratorLinkedListThruForeach:" + interval+" ms");
}
/**
* 通過另外一種for迴圈來遍歷LinkedList
*/
private static void iteratorThroughFor2(LinkedList<Integer> list) {
if (list == null)
return ;
long start = System.currentTimeMillis();
for (Integer integ : list)
;
long end = System.currentTimeMillis();
long interval = end - start;
System.out.println("iteratorThroughFor2:" + interval+" ms");
}
/**
* 通過pollFirst()來遍歷LinkedList
*/
private static void iteratorThroughPollFirst(LinkedList<Integer> list) {
if (list == null)
return ;
long start = System.currentTimeMillis();
while(list.pollFirst() != null)
;
long end = System.currentTimeMillis();
long interval = end - start;
System.out.println("iteratorThroughPollFirst:" + interval+" ms");
}
/**
* 通過pollLast()來遍歷LinkedList
*/
private static void iteratorThroughPollLast(LinkedList<Integer> list) {
if (list == null)
return ;
long start = System.currentTimeMillis();
while(list.pollLast() != null)
;
long end = System.currentTimeMillis();
long interval = end - start;
System.out.println("iteratorThroughPollLast:" + interval+" ms");
}
/**
* 通過removeFirst()來遍歷LinkedList
*/
private static void iteratorThroughRemoveFirst(LinkedList<Integer> list) {
if (list == null)
return ;
long start = System.currentTimeMillis();
try {
while(list.removeFirst() != null)
;
} catch (NoSuchElementException e) {
}
long end = System.currentTimeMillis();
long interval = end - start;
System.out.println("iteratorThroughRemoveFirst:" + interval+" ms");
}
/**
* 通過removeLast()來遍歷LinkedList
*/
private static void iteratorThroughRemoveLast(LinkedList<Integer> list) {
if (list == null)
return ;
long start = System.currentTimeMillis();
try {
while(list.removeLast() != null)
;
} catch (NoSuchElementException e) {
}
long end = System.currentTimeMillis();
long interval = end - start;
System.out.println("iteratorThroughRemoveLast:" + interval+" ms");
}
}
測試結果如下:
iteratorLinkedListThruIterator:10 ms
iteratorLinkedListThruForeach:414648 ms
iteratorThroughFor2:10 ms
iteratorThroughPollFirst:8 ms
iteratorThroughPollLast:10 ms
iteratorThroughRemoveFirst:7 ms
iteratorThroughRemoveLast:6 ms
由此可見,遍歷LinkedList時,使用removeFirst()或removeLast()效率最高。但是用它們遍歷會刪除原始資料;若只是單純的取資料,而不刪除,建議用迭代器方式或者for-each方式。
無論如何,千萬不要用隨機訪問去遍歷LinkedList!除非腦門兒被驢給踢了... ...
LinkedList原始碼就討論這麼多,如果錯誤,歡迎留言指正~
_____________________________________________________________________________________________________________________________________________________
-----樂於分享,共同進步!