Java 集合源码解析系列:
- 拆行解码 Java 集合源码之总览
- 拆行解码 Java 集合源码之 Collection 的三大体系
- 拆行解码 Java 集合源码之迭代器
- 拆行解码 Java 集合源码之 ArrayList
- 拆行解码 Java 集合源码之 LinkedList
- 拆行解码 Java 集合源码之 HashMap
- 拆行解码 Java 集合源码之 Hashtable
- 拆行解码 Java 集合源码之 LinkedHashMap
- 拆行解码 Java 集合源码之 PriorityQueue
- 拆行解码 Java 集合源码之 ArrayDeque
特性
-
双向链表
由于是链表,所以不存在扩容上的问题。
-
元素允许为 null。
-
不支持随机访问。
与 ArrayList 直接继承 AbstracList 不同, LinkedList 与 AbstractList 之间还有一层类 :AbstractSequentialList:标明该集合支持顺序,不支持随机。
-
同时实现 List 和 Deque,具备列表和双写队列的作用。
-
非线程安全。可使用 Collections.synchronizedList 包装为线程安全列表。
源码解析
public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
transient int size = 0;
/**
* Pointer to first node.
*/
transient Node<E> first;
/**
* Pointer to last node.
*/
transient Node<E> last;
public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
}
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;
}
}
单个操作
检查索引
指定索引操作单个元素时,需要检查索引是否溢出。而添加和删除的索引范围不同,前者允许索引 == size,存在两套校验。
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
private boolean isPositionIndex(int index) {
return index >= 0 && index <= 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));
}
public api
可以看到,由于实现了 List 和 Deque,关于元素操作的方法很多。
但是存在一些规律:
- Deque 方法的实现,可以由 List 的方法做到。
- List 和 Deque 无论如何,其实都是操作链表的 Node。无非几种情况,一一都有可复用的私有方法。
// 列表相关操作
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);
}
public void addFirst(E e) {
linkFirst(e);
}
public void addLast(E e) {
linkLast(e);
}
public boolean add(E e) {
linkLast(e);
return true;
}
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 {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
// 队列相关操作
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;
}
// 其实和 offer 是一样
public boolean offerLast(E e) {
addLast(e);
return true;
}
// 其实和 poll 是一样
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();
}
public boolean removeFirstOccurrence(Object o) {
return remove(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;
}
private api
节点新增、移除的几种 api:
- linkFirst:新增一个节点,作为头结点;
- linkLast:新增一个节点,作为尾节点;
- linkBefore:在指定节点前新增一个节点;
- unlinkFirst:移除头结点;
- unlinkLast:移除尾节点;
- unlink:移除指定节点。
/**
* Links e as first element.
*/
private void linkFirst(E e) {
final Node<E> f = first;
// 原头结点作为新节点的后继节点
final Node<E> newNode = new Node<>(null, e, f);
first = newNode; // 设为头结点
if (f == null)
// 原链表为空, 同时设为尾节点
last = newNode;
else
// 新节点设为原头结点的前驱节点
f.prev = newNode;
size++;
modCount++;
}
/**
* Links e as last element.
*/
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++;
}
/**
* Inserts element e before non-null Node succ.
*/
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
// 调用方需要保证 succ 不为空
final Node<E> pred = succ.prev;
// pred -> succ
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
// pred -> newNode -> succ
if (pred == null)
// succ 为原头结点, 则 newNode 设置为新头结点
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
/**
* Unlinks non-null first node f.
*/
private E unlinkFirst(Node<E> f) {
// 调用方需要保证 f 是头结点,且不为空
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
// first 也是尾结点(即只有一个节点);删除后链表为空
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
/**
* Unlinks non-null last node l.
*/
private E unlinkLast(Node<E> l) {
// 调用方需要保证 l 是尾结点,且不为空
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev;
if (prev == null)
// last 也是头结点(即只有一个节点);删除后链表为空
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
/**
* Unlinks non-null node x.
*/
E unlink(Node<E> x) {
// 确保节点不为空
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
// prev -> x -> next
if (prev == null) {
// 前驱结点不为空, 说明 x 是头结点。next 设为新的头结点
first = next;
} else {
// prev -> next; 待处理x -> next
prev.next = next;
x.prev = null;
}
if (next == null) {
// 后继结点不为空, 说明 x 是尾结点。prev 设为新的尾结点
last = prev;
} else {
// prev -> next; 断开x -> next
next.prev = prev;
x.next = null;
}
// 节点数据删除
x.item = null;
size--;
modCount++;
return element;
}
批处理
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) {
@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;
}
// pred 现在是添加的最后一个节点
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
public void clear() {
// Clearing all of the links between nodes is "unnecessary", but:
// - helps a generational GC if the discarded nodes inhabit
// more than one generation
// - is sure to free memory even if there is a reachable Iterator
// 清除节点之间的链接本身是没有必要的。但是可以帮助节点处于不同GC分代时的GC
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}
节点、索引的查询
直接操作头尾节点
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;
}
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
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 element() {
return getFirst();
}
遍历查询
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
Node<E> node(int index) {
// 前提条件:assert isElementIndex(index);
// 根据 index 在中间点的左右,来决定是从前往后,还是从后往前遍历
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
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;
}
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;
}
倒序迭代器
基于 Deque 的实现, LinkedList 实现了倒序遍历的 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();
}
}
AbstractSequentialList
由于是顺序的,AbstractSequentialList 可以使用 ListIterator 实现根据索引添加、修改、删除:listIterator(index).next()。
AbstractList 为啥不提供这个默认实现?
猜测,可能是本身还包含随机访问实现的可能,那么不能单纯的使用迭代器(可能涉及到元素搬移等)。所以不提供默认实现,这点从 AbstractList 相关方法的注释中可见一二。
public E get(int index) {
try {
return listIterator(index).next();
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}
public E set(int index, E element) {
try {
ListIterator<E> e = listIterator(index);
E oldVal = e.next();
e.set(element);
return oldVal;
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}
public void add(int index, E element) {
try {
listIterator(index).add(element);
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}
public E remove(int index) {
try {
ListIterator<E> e = listIterator(index);
E outCast = e.next();
e.remove();
return outCast;
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}
public boolean addAll(int index, Collection<? extends E> c) {
try {
boolean modified = false;
ListIterator<E> e1 = listIterator(index);
for (E e : c) {
e1.add(e);
modified = true;
}
return modified;
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}