LinkedList源码分析
Posted zitai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LinkedList源码分析相关的知识,希望对你有一定的参考价值。
简介
LinkedList是以双向链表为数据结构的容器。它可以进行堆栈、队列、双端队列的操作。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
LinkedList 继承AbstractSequentialList
,该被继承类是抽象类,是在迭代器的基础上实现的get、set、add和remove方法。该抽象类更多信息:AbstractSequentialList
LinkedList实现 Deque
接口:能当做双端队列使用。
LinkedList实现 Cloneable
接口:具有克隆功能。
LinkedList实现 Serializable
接口:具有序列化功能。
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()
属性
//链表节点
transient int size = 0;
//双向链表表头节点
transient Node<E> first;
//双向链表表尾节点
transient Node<E> last;
//序列号
private static final long serialVersionUID = 876323262645176354L;
Node节点
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;
}
特别说明
/**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first;
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
由注释内容知道,当双链表为空的时候,first和last都为空;当双链表都不为空的时候,first的前节点指针为空,first的数据不为空,last的后节点指针为空,last的数据不为空。
构造函数
//创建一个空的链表
public LinkedList() {
}
//将其他容器数据放入初始化链表中
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
//在first节点前面添加节点
private void linkFirst(E e) {
//保存first节点
final Node<E> f = first;
//创建节点,该节点前节点为null,后节点为first
final Node<E> newNode = new Node<>(null, e, f);
//更换first节点
first = newNode;
//若该链表为空,则也把last更换为新节点
if (f == null)
last = newNode;
else
//若该链表非空,则将原本first的前指针指向新的的first
f.prev = newNode;
//节点数++
size++;
modCount++;
}
//在last节点后面添加节点
void linkLast(E e) {
//保存last节点
final Node<E> l = last;
//创建节点,该节点前节点为last,后节点为null
final Node<E> newNode = new Node<>(l, e, null);
//更换last节点
last = newNode;
//若该链表为空,则也把first更换为新节点
if (l == null)
first = newNode;
else
//若该链表非空,则将原本last的后指针指向新的的last
l.next = newNode;
//节点数++
size++;
modCount++;
}
//在指定节点前添加一个新节点
void linkBefore(E e, Node<E> succ) {
//获取指定节点的前节点pre
final Node<E> pred = succ.prev;
//创建节点,该节点前节点为pre,后节点为指定节点succ
final Node<E> newNode = new Node<>(pred, e, succ);
//更改指定节点前指针,为e
succ.prev = newNode;
//若succ为first或者改链表节点数为1时,修改first节点
if (pred == null)
first = newNode;
else
//更改前节点pre的后指针为新节点newNode
pred.next = newNode;
size++;
modCount++;
}
//移除first节点
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
//前提就是f为first且不为空
//获取first节点数据
final E element = f.item;
//获取first节点指向的下一个节点
final Node<E> next = f.next;
//将first节点置空
f.item = null;
f.next = null; // help GC
//first赋值为下一个节点next
first = next;
//若next为空,即链表长度为1,为将last置空
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
//移除last节点
private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
//前提就是l为last且不为空
final E element = l.item;
//获取last节点指向的前一个节点
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
//last赋值为前一个节点prev
last = prev;
//若prev为空,即链表长度为1,为将first置空
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
//移除节点
E unlink(Node<E> x) {
//获取该移除节点数据、前节点、后节点
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
//若移除节点为first,修改first为后节点
if (prev == null) {
first = next;
} else {
//前节点与后节点互连
prev.next = next;
//将移除的节点的前指针置空
x.prev = null;
}
//若移除节点为last,则修改last为前节点
if (next == null) {
last = prev;
} else {
//前节点与后节点互连
next.prev = prev;
//将移除的节点的后指针置空
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}
//获取first节点数据
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
//获取last节点数据
public E getLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return l.item;
}
//移除first节点
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
//移除last节点
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);
}
//检测是否存在数据o
public boolean contains(Object o) {
return indexOf(o) != -1;
}
//返回链表节点数
public int size() {
return size;
}
//往链表末尾添加数据
public boolean add(E e) {
linkLast(e);
return true;
}
//移除指定数据的节点
public boolean remove(Object o) {
//数据为null
if (o == null) {
//遍历链表
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null) {
//调用移除节点方法
unlink(x);
return true;
}
}
} else { //数据不为null
//遍历链表
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
//调用移除节点方法
unlink(x);
return true;
}
}
}
return false;
}
//在链表尾部添加其他容器的数据
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;
//pre为插入位置的前节点,succ为插入位置的后节点
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;
}
//若succ为null,则表示插入位置为size,需要重新对last赋值
if (succ == null) {
last = pred;
} else {
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;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}
//根据位置获取节点
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;
}
//根据位置添加数据
public void add(int index, E element) {
checkPositionIndex(index);
//若位置为链表尾部,直接调用linkLast
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
//根据位置移除节点
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
//判断索引是否非法
private boolean isElementIndex(int index) {
return index >= 0 && 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));
}
//根据索引获取节点
Node<E> node(int index) {
//当索引小于节点数一半,则从first节点向后开始寻找
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
//当索引大于等于节点数一半,则从last节点向前开始寻找
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;
//通过遍历数据来寻找,数据照旧有两种情况,null和非null
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;
//通过遍历数据来寻找,数据照旧有两种情况,null和非null
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;
}
//获取first节点的数据
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
//获取first节点的数据
public E element() {
return getFirst();
}
//移除first节点
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
//移除first节点
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;
}
//查看first节点数据
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
//查看last节点数据
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;
}
//获取next为index的迭代器
public ListIterator<E> listIterator(int index) {
checkPositionIndex(index);
return new ListItr(index);
}
//获取反向迭代器
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();
}
}
//调用父类克隆函数
private LinkedList<E> superClone() {
try {
return (LinkedList<E>) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
// 克隆函数。返回LinkedList的克隆对象。
public Object clone() {
LinkedList<E> clone = superClone();
// 将克隆置于“原始”状态
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
// 将链表中所有节点的数据都添加到克隆对象中
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item);
return clone;
}
//返回LinkedList的Object[]数组
public Object[] toArray() {
// 新建Object[]数组
Object[] result = new Object[size];
int i = 0;
// 将链表中所有节点的数据都添加到Object[]数组中
for (Node<E> x = first; x != null; x = x.next)
result[i++] = x.item;
return result;
}
// 返回LinkedList的模板数组。所谓模板数组,即可以将T设为任意的数据类型
public <T> T[] toArray(T[] a) {
// 若数组a的大小 < LinkedList的元素个数(意味着数组a不能容纳LinkedList中全部元素)
// 则新建一个T[]数组,T[]的大小为LinkedList大小,并将该T[]赋值给a。
if (a.length < size)
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
int i = 0;
// 将链表中所有节点的数据都添加到数组a中
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;
}
// java.io.Serializable的写入函数
// 将LinkedList的“容量,所有的元素值”都写入到输出流中
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out any hidden serialization magic
s.defaultWriteObject();
// 写入节点数
s.writeInt(size);
// 将链表中所有节点的数据都写入到输出流中
for (Node<E> x = first; x != null; x = x.next)
s.writeObject(x.item);
}
// java.io.Serializable的读取函数:根据写入方式反向读出
// 先将LinkedList的“容量”读出,然后将“所有的元素值”读出
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in any hidden serialization magic
s.defaultReadObject();
// 从输入流中读取“容量”
int size = s.readInt();
// 从输入流中将“所有的元素值”并逐个添加到链表中
for (int i = 0; i < size; i++)
linkLast((E)s.readObject());
}
引用其他博客的总结:skywang12345:
-
LinkedList是通过双向链表来实现,其中链表节点为node,为LinkedList的内部类,属性包括该节点值、上一个节点,下一个节点。
-
从LinkedList的实现方式中可以发现,它不存在LinkedList容量不足的问题。
-
LinkedList的克隆函数,即是将全部元素克隆到一个新的LinkedList对象中。
-
LinkedList实现java.io.Serializable。当写入到输出流时,先写入“容量”,再依次写入“每一个节点保护的值”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。
-
从LinkedList的实现方式中可以发现,它不存在LinkedList容量不足的问题。
-
由于LinkedList实现了Deque,而Deque接口定义了在双端队列两端访问元素的方法。提供插入、移除和检查元素的方法。每种方法都存在两种形式:一种形式在操作失败时抛出异常,另一种形式返回一个特殊值(null 或 false,具体取决于操作)。
第一个元素(头部) 最后一个元素(尾部) 抛出异常 特殊值 抛出异常 特殊值 插入 addFirst(e) offerFirst(e) addLast(e) offerLast(e) 移除 removeFirst() pollFirst() removeLast() pollLast() 检查 getFirst() peekFirst() getLast() peekLast()
-
LinkedList可以作为FIFO(先进先出)的队列,作为FIFO的队列时,下表的方法等价:
队列方法 等效方法 add(e) addLast(e) offer(e) offerLast(e) remove() removeFirst() poll() pollFirst() element() getFirst() peek() peekFirst()
-
LinkedList可以作为LIFO(后进先出)的栈,作为LIFO的栈时,下表的方法等价:
栈方法 等效方法 push(e) addFirst(e) pop() removeFirst() peek() peekFirst()
以上是关于LinkedList源码分析的主要内容,如果未能解决你的问题,请参考以下文章