上一章学习了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: ms
iteratorThroughRemoveFirst: ms
iteratorThroughRemoveLast: ms

由此可见,遍历LinkedList时,使用removeFirst()或removeLast()效率最高。但是用它们遍历会删除原始数据;若只是单纯的取数据,而不删除,建议用迭代器方式或者for-each方式。

无论如何,千万不要用随机访问去遍历LinkedList!除非脑门儿被驴给踢了... ...

LinkedList源码就讨论这么多,如果错误,欢迎留言指正~

java集合框架04——LinkedList和源码分析的更多相关文章

  1. java集合框架03——ArrayList和源码分析

    最近忙着替公司招人好久没写了,荒废了不好意思. 上一章学习了Collection的架构,并阅读了部分源码,这一章开始,我们将对Collection的具体实现进行详细学习.首先学习List.而Array ...

  2. java集合系列之LinkedList源码分析

    java集合系列之LinkedList源码分析 LinkedList数据结构简介 LinkedList底层是通过双端双向链表实现的,其基本数据结构如下,每一个节点类为Node对象,每个Node节点包含 ...

  3. Java集合系列[2]----LinkedList源码分析

    上篇我们分析了ArrayList的底层实现,知道了ArrayList底层是基于数组实现的,因此具有查找修改快而插入删除慢的特点.本篇介绍的LinkedList是List接口的另一种实现,它的底层是基于 ...

  4. Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例

    java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...

  5. Java集合框架之LinkedList浅析

    Java集合框架之LinkedList浅析 一.LinkedList综述: 1.1LinkedList简介 同ArrayList一样,位于java.util包下的LinkedList是Java集合框架 ...

  6. Java集合系列[4]----LinkedHashMap源码分析

    这篇文章我们开始分析LinkedHashMap的源码,LinkedHashMap继承了HashMap,也就是说LinkedHashMap是在HashMap的基础上扩展而来的,因此在看LinkedHas ...

  7. java集合系列之ArrayList源码分析

    java集合系列之ArrayList源码分析(基于jdk1.8) ArrayList简介 ArrayList时List接口的一个非常重要的实现子类,它的底层是通过动态数组实现的,因此它具备查询速度快, ...

  8. java集合框架之LinkedList

    参考http://how2j.cn/k/collection/collection-linkedlist/370.html LinkedList 与 List接口 与ArrayList一样,Linke ...

  9. Java集合系列:-----------03ArrayList源码分析

    上一章,我们学习了Collection的架构.这一章开始,我们对Collection的具体实现类进行讲解:首先,讲解List,而List中ArrayList又最为常用.因此,本章我们讲解ArrayLi ...

随机推荐

  1. RabbitMQ消息队列(二):”Hello, World“

    本文将使用Python(pika 0.9.8)实现从Producer到Consumer传递数据”Hello, World“. 首先复习一下上篇所学:RabbitMQ实现了AMQP定义的消息队列.它实现 ...

  2. 写了一个复杂的sql语句

    $sp_sql = "select sp_ProductNo, sp_ProductName,sp_Standard,sp_Unit,sum(sp_Amount) as amount fro ...

  3. Chrome Timeline的指标说明:Blocked、Connect、Send、Wait、Receive

    Blocked time includes any pre-processing time (such as cache lookup) and the time spent waiting for ...

  4. iOS 错误之 NSObject 、CGFloat

    需要添加 #import <Foundation/Foundation.h> #import <UIKit/UIKit.h>

  5. iOS 解决一个复杂bug 之 计分卡

    由于该模块界面和业务逻辑都很复杂,并且整个界面设计和业务逻辑都在ViewController(下面简称为VC)里面完成.该VC共有3000多行,一个函数几百张的也有.所以,解决起来真是头疼. 1. 问 ...

  6. 模块划分--MVVM指南(课程学习)

    实现流水化开发,需要使用“模块划分”的程序开发方式.如此,团队里的每个人负责某项\某几项特定的技术领域,在特定的技术领域更加专业.这样,每个人的效率更高.在专业的技能更熟练,更深入,也会提高队员的成就 ...

  7. 1.4.2.1. FILES(Core Data 应用程序实践指南)

    #define debug 1 #pragma mark - FILES NSString *storeFilename = @"Grocery-Dude.sqlite";

  8. endnote X7 加入文献

    endnote可以管理文献,并且在word中方便的添加参考文献. 1.加入文献: 2.导入以后可以创建自己的group,然后把导入的参考文献拖到group里,这样方便在插入参考文献的时候用group名 ...

  9. 读jQuery之二十(Deferred对象)

    Deferred对象是由$.Deferred构造的,$.Deferred被实现为简单工厂模式. 它用来解决JS中的异步编程,它遵循 Common Promise/A 规范.实现此规范的还有 when. ...

  10. 一个简单的Java集合范围过滤的多个方式对比

    在一个项目里面有这么一个技术需求: 1.集合中元素个数,10M 2.根据上限和下限从一个Set中过滤出满足要求的元素集合. 实际这个是个很典型的技术要求, 之前的项目也遇见过,但是因为当时的类库不多, ...