JAVA 集合类(java.util)源码阅读笔记------LinkedList
Posted Itzel_yuki
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA 集合类(java.util)源码阅读笔记------LinkedList相关的知识,希望对你有一定的参考价值。
一、继承关系
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
(1)继承自AbstractSequentialList抽象类(该类继承自AbstractList抽象类);实现了List、Deque、Cloneable和Serializable接口,对随机get、set、remove等做了基本实现。
(2)AbstractSequentialList抽象类:定义了具体方法get()、set()、add()、remove()、addAll()(提供对list的随机访问功能)和抽象方法abstract ListIterator<E> listIterator(int index)。
(3)Deque:双向队列,可以用作栈。继承自Queue接口,Queue接口又继承自Collection接口。
(4)实现方式是采用一个链表的形式。
(5)LinkedList可以被当作堆栈(实现了Deque接口)、队列或双端队列进行操作。
二、成员变量
transient int size = 0;//包含元素的个数
transient Node<E> first;//指向链表的第一个元素的指针
transient Node<E> last;//指向链表的最后一个元素的指针
三、方法说明
(1)addFirst:链表头部添加一个新元素,调用私有方法linkFirst实现
public void addFirst(E e)
linkFirst(e);
//linkFirst:在链表首添加一个元素
private void linkFirst(E e)
final Node<E> f = first;
//new Node<>(指向前一个节点的指针,数据,指向后一个节点的指针)
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
//链表原先为空,现在添加了一个节点,last指针和first指针都指向该节点
if (f == null)
last = newNode;
//原先的首节点的prev指针指向新节点
else
f.prev = newNode;
size++;
//修改次数+1
modCount++;
(2)addLast、add:在链表尾部添加一个新节点,调用私有方法linkLast实现
public void addLast(E e)
linkLast(e);
类似的还有add方法也是调用linkLast实现
public boolean add(E e)
linkLast(e);
return true;
linkLast:在链表的最后添加一个节点
void linkLast(E e)
final Node<E> l = last;
//新节点的prev指针指向原先的最后一个节点
final Node<E> newNode = new Node<>(l, e, null);
//修改last指针指向新的最后一个节点
last = newNode;
if (l == null)
first = newNode;
//原先的最后一个节点的next指针指向新节点
else
l.next = newNode;
size++;
modCount++;
(3)linkBefore:在succ节点之前添加节点,如果succ为null会抛出异常
void linkBefore(E e, Node<E> succ)
// assert succ != null;
final Node<E> pred = succ.prev;//succ的前一个节点
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
//succ是首节点
if (pred == null)
first = newNode;
//succ的前一个节点的next指向新节点
else
pred.next = newNode;
size++;
modCount++;
(4)removeFirst:删除链表的头节点
public E removeFirst()
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
//unlinkFirst:删除链表中第一个节点,并取消链接(prev和next),私有方法,供removeLast()调用
//使用前提:f!=null,否则会抛出异常;并且f是链表的第一个节点,否则结果会删除链表首节点到f位置的所有节点(first=f.next)
private E unlinkFirst(Node<E> f)
// assert f == first && 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)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
(5)removeLast:删除链表的最后一个节点
public E removeLast()
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
//unlinkLast:删除链表的最后一个节点,并删除链接,私有方法,供removeFirst方法调用
//使用前提:f!=null,否则会抛出异常;并且l是链表的最后一个节点,否则会删除f到链表尾部的所有节点(last=l.prev)
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;
(6)unlink:删除一个节点,并删除该节点的prev和next链接,修改前后节点的链接
//x!=null,否则会抛出异常
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;
//x是首节点
if (prev == null)
first = next;
else
//取消prev和x两个节点之间的链接
prev.next = next;
x.prev = null;
//x是尾节点
if (next == null)
last = prev;
else
//取消next和x两个节点之间的链接
next.prev = prev;
x.next = null;
x.item = null;
//链表size减一
size--;
//增加修改次数
modCount++;
//返回删除节点的数据部分
return element;
(7)删除指定的节点,需要调用unlink
public boolean remove(Object o)
//当o==null时,通过==判断x.item与o是否相当,否则,通过o.equals(x.item)来判断是否相等
if (o == 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;
(8)在指定的index处添加多个节点
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指向链表中第index个节点,pred指向succ节点的前一个节点,c中的元素需要添加在pred和succ之间
succ = node(index);
pred = succ.prev;
//逐个添加,将pred与新节点之间的链接建立起来
for (Object o : a)
@SuppressWarnings("unchecked") E e = (E) o;
//新节点的prev指向pred
Node<E> newNode = new Node<>(pred, e, null);
//添加的是首节点
if (pred == null)
first = newNode;
else
//pred的next指向新节点
pred.next = newNode;
//pred向后移动
pred = newNode;
//将添加的最后一个节点与succ之间的链接建立起来
if (succ == null)
last = pred;
else
pred.next = succ;
succ.prev = pred;
//修改链表的大小
size += numNew;
//修改次数+1
modCount++;
return true;
(9)重写了Object的clone方法,该类的父类或者父接口实现了cloneable接口,因此该类间接的实现了cloneable接口
public Object clone()
LinkedList<E> clone = superClone();
// Put clone into "virgin" state
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
// 深复制,但是如果item是一个引用类型数据,则原链表中节点的item与新clone的链表节点中item指向的仍然是同一个对象。
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item);
return clone;
四、内部类
(1) Node:链表的节点类,是一个有两个指针的节点
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;
(2) ListItr:链表的双向迭代器
private class ListItr implements ListIterator<E>
private Node<E> lastReturned;//上一次操作的节点
private Node<E> next;//指向节点的指针
private int nextIndex;//next是链表的第几个节点
//为了检查当一个线程在对该链表操作时,是否有另一个线程在对该链表进行增删改操作,如果有,就抛出ConcurrentModificationException异常
private int expectedModCount = modCount;
//index指向的是该节点器的起始节点在原链表中的位置
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的前一个节点
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
public boolean hasPrevious()
return nextIndex > 0;
public E previous()
checkForComodification();
if (!hasPrevious())
throw new NoSuchElementException();
//lastReturned指向next同一个节点
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();
//检查lastReturned是否为空
if (lastReturned == null)
throw new IllegalStateException();
Node<E> lastNext = lastReturned.next;
unlink(lastReturned);
//当上一次调用的是next时,next!=lastReturned;当上一次调用的是previous时,next==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++;
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();
(3)链表逆向迭代器:通过itr.previous()实现
/**
* Adapter to provide descending iterators via 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();
(4)LLSpliterator: 并行迭代器
java1.8新添加的,在Collection接口中用default关键字定义,提供了默认实现。
以上是关于JAVA 集合类(java.util)源码阅读笔记------LinkedList的主要内容,如果未能解决你的问题,请参考以下文章
JAVA 集合类(java.util)源码阅读笔记------ArrayList
JAVA 集合类(java.util)源码阅读笔记------Hashtable
JAVA 集合类(java.util)源码阅读笔记------HashMap
JAVA 集合类(java.util)源码阅读笔记------WeakHashMap