LinkedList源码分析
继承实现
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Queue<E>, Cloneable, Serializable
LinkedList
是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列列或双端队列进行操作。LinkedList
实现 List 接⼝口,能对它进行队列操作。LinkedList
实现 Deque 接⼝口,双向队列,它支持从两个端点方向检索和插入元素。LinkedList
实现了 Cloneable 接口,即覆盖了函数clone()
,能克隆。LinkedList
实现 java.io.Serializable 接口,这意味着LinkedList
支持序列化,能通过序列化去传输。
重要属性
// 链表的大小
transient int size = 0;
// 头结点
transient Link<E> voidLink;
transient:不会参与序列化
内部类
Link
private static final class Link<ET> {
ET data; // 数据域
Link<ET> previous, next; // 前驱和后继
Link(ET o, Link<ET> p, Link<ET> n) {
data = o;
previous = p;
next = n;
}
}
LinkedList
存储的数据是以链表形式存储的,每一个节点对应的类就是Link
很明显,每一个
Link
节点包含一个数据域和两个指针域。
LinkIterator
LinkedList
对应的迭代器,用于遍历
重要属性
int pos, expectedModCount; // 位置和扩展的计数器
final LinkedList<ET> list; // 迭代器自己的LinkedList
Link<ET> link, lastLink; // 当前节点和最后节点
构造方法
LinkIterator(LinkedList<ET> object, int location) {
list = object; // 保存传入的LinkedList
expectedModCount = list.modCount; // 保存传入的LinkedList的计数器
if (location >= 0 && location <= list.size) { // 确保location不越界
if (location < list.size / 2) {
/*
如果location = 0
不会执行下面的循环
如果location >= 1
执行下面循环,但现在link = null,会报NullPointerException【已验证】
如果listIterator方法传入0,location = 0,不会报异常。但不会执行下面循环。
如果传入>0,会报NullPointerException
*/
for (pos = -1; pos + 1 < location; pos++) {
link = link.next;
}
} else {
/*
如果location = 0 && list.size == [0, 1]
会执行下面的循环
如果location > 0 && location >= list.size/2 && location <= list.size
也会执行下面的循环
但总的来说,因为link属性为null。所以无论.next还是.previous都会报异常。
*/
for (pos = list.size; pos >= location; pos--) {
link = link.previous;
}
}
/*
总结:绝大多数时候,调用listIterator()方法默认是不会传参数的,但其内部默认传的是0.
因此基本上走的是 if (location < list.size / 2)判断,而正是因为location = 0,所以里面的for循环是不会走的。
相当于,这个if循环就是个摆设!
这个构造方法的存在的意义也就是将传来的object集合存储,赋值给list属性!
*/
} else {
throw new IndexOutOfBoundsException();
}
}
// 添加一个节点
// 添加新节点是添加在link位置之后的
public void add(ET object) {
if (expectedModCount == list.modCount) {
Link<ET> next = link.next;
// 新节点在link和link.next之间
Link<ET> newLink = new Link<ET>(object, link, next);
// link和newLink进行双向链接
link.next = newLink;
next.previous = newLink;
// 让新节点成当前节点
link = newLink;
lastLink = null;
pos++; // link位置++
expectedModCount++;
list.size++;
list.modCount++;
} else {
throw new ConcurrentModificationException();
}
}
// 是否有下一个节点(不包括头节点)
public boolean hasNext() {
// 这是双向链表,所以如果当前节点的下一个节点不是头结点
// 就说明还有下一个节点
return link.next != list.voidLink;
}
// 是否有上一个节点(不包括头节点)
public boolean hasPrevious() {
// 头结点也是一个节点,所以当前节点不是头结点的话
// 最起码前面还有一个头结点存在
return link != list.voidLink;
}
// 获取下一个节点的数据
public ET next() {
if (expectedModCount == list.modCount) {
LinkedList.Link<ET> next = link.next; // 首先获取当前节点的下一个节点
if (next != list.voidLink) { // 然后判断这个"下一个节点"是不是有效的
lastLink = link = next; // 确定"下一个节点"有效,赋值lastLink和link
pos++; // 移位
return link.data; // 返回"下一个节点"的数据
}
throw new NoSuchElementException();
}
throw new ConcurrentModificationException();
}
public int nextIndex() {
return pos + 1;
}
// 获取上一个节点的数据
public ET previous() {
if (expectedModCount == list.modCount) {
// 判断是否还有前一个节点,判断标准是当前节点而非当前节点的前一个节点
// 因为对于上一个节点来说,头节点也可以是上一个节点
if (link != list.voidLink) {
lastLink = link; // 将当前节点设置为最后节点
link = link.previous; // 将上一个节点设置为当前节点
pos--;
return lastLink.data; // 返回当前节点的数据
}
throw new NoSuchElementException();
}
throw new ConcurrentModificationException();
}
public int previousIndex() {
return pos;
}
// 删除一个节点
public void remove() {
if (expectedModCount == list.modCount) {
// 删除的是lastLink
if (lastLink != null) {
// 取出lastLink的 前一个/后一个 节点
Link<ET> next = lastLink.next;
Link<ET> previous = lastLink.previous;
// 并将前一节点和后一节点衔接起来,相当于lastLink已经不需要了
next.previous = previous;
previous.next = next;
if (lastLink == link) {
pos--;
}
// 将前一节点设为当前节点,lastLink置为null
link = previous;
lastLink = null;
expectedModCount++;
list.size--;
list.modCount++;
} else {
throw new IllegalStateException();
}
} else {
throw new ConcurrentModificationException();
}
}
// 设置值给lastLink.data
public void set(ET object) {
if (expectedModCount == list.modCount) {
if (lastLink != null) {
lastLink.data = object;
} else {
throw new IllegalStateException();
}
} else {
throw new ConcurrentModificationException();
}
}
- 关于这个
LinkIterator
感到很奇怪,因为没看到让link
和lastLink
不为null
的地方。无论是构造方法还是功能功能方法,上来都是直接使用。但经我测试会报NullPointerException
!
功能方法
// 添加一个节点
// 添加新节点是添加在link位置之后的
public void add(ET object) {
if (expectedModCount == list.modCount) {
Link<ET> next = link.next;
// 新节点在link和link.next之间
Link<ET> newLink = new Link<ET>(object, link, next);
// link和newLink进行双向链接
link.next = newLink;
next.previous = newLink;
// 让新节点成当前节点
link = newLink;
lastLink = null;
pos++; // link位置++
expectedModCount++;
list.size++;
list.modCount++;
} else {
throw new ConcurrentModificationException();
}
}
// 是否有下一个节点(不包括头节点)
public boolean hasNext() {
// 这是双向链表,所以如果当前节点的下一个节点不是头结点
// 就说明还有下一个节点
return link.next != list.voidLink;
}
// 是否有上一个节点(不包括头节点)
public boolean hasPrevious() {
// 头结点也是一个节点,所以当前节点不是头结点的话
// 最起码前面还有一个头结点存在
return link != list.voidLink;
}
// 获取下一个节点的数据
public ET next() {
if (expectedModCount == list.modCount) {
LinkedList.Link<ET> next = link.next; // 首先获取当前节点的下一个节点
if (next != list.voidLink) { // 然后判断这个"下一个节点"是不是有效的
lastLink = link = next; // 确定"下一个节点"有效,赋值lastLink和link
pos++; // 移位
return link.data; // 返回"下一个节点"的数据
}
throw new NoSuchElementException();
}
throw new ConcurrentModificationException();
}
public int nextIndex() {
return pos + 1;
}
// 获取上一个节点的数据
public ET previous() {
if (expectedModCount == list.modCount) {
// 判断是否还有前一个节点,判断标准是当前节点而非当前节点的前一个节点
// 因为对于上一个节点来说,头节点也可以是上一个节点
if (link != list.voidLink) {
lastLink = link; // 将当前节点设置为最后节点
link = link.previous; // 将上一个节点设置为当前节点
pos--;
return lastLink.data; // 返回当前节点的数据
}
throw new NoSuchElementException();
}
throw new ConcurrentModificationException();
}
public int previousIndex() {
return pos;
}
// 删除一个节点
public void remove() {
if (expectedModCount == list.modCount) {
// 删除的是lastLink
if (lastLink != null) {
// 取出lastLink的 前一个/后一个 节点
Link<ET> next = lastLink.next;
Link<ET> previous = lastLink.previous;
// 并将前一节点和后一节点衔接起来,相当于lastLink已经不需要了
next.previous = previous;
previous.next = next;
if (lastLink == link) {
pos--;
}
// 将前一节点设为当前节点,lastLink置为null
link = previous;
lastLink = null;
expectedModCount++;
list.size--;
list.modCount++;
} else {
throw new IllegalStateException();
}
} else {
throw new ConcurrentModificationException();
}
}
// 设置值给lastLink.data
public void set(ET object) {
if (expectedModCount == list.modCount) {
if (lastLink != null) {
lastLink.data = object;
} else {
throw new IllegalStateException();
}
} else {
throw new ConcurrentModificationException();
}
}
ReverseLinkIterator
重要属性
// 存储LinkedList的属性
private final LinkedList<ET> list;
// 节点
private Link<ET> link;
// 是否可以删除
private boolean canRemove;
构造方法
ReverseLinkIterator(LinkedList<ET> linkedList) {
list = linkedList; // 存储集合
expectedModCount = list.modCount;
link = list.voidLink; // 存储头节点
canRemove = false;
}
功能方法
// 是否有上一个节点
public boolean hasNext() {
// 因为是reverse,所以是previous
return link.previous != list.voidLink;
}
public ET next() {
if (expectedModCount == list.modCount) {
if (hasNext()) {
link = link.previous; // 获取到上一个节点
canRemove = true;
return link.data; // 返回上一个节点的数据
}
throw new NoSuchElementException();
}
throw new ConcurrentModificationException();
}
// 移除掉当前节点——link节点
public void remove() {
if (expectedModCount == list.modCount) {
if (canRemove) { // 如果可以删除,调用next时canRemove为true
// 获取到link的前后节点
Link<ET> next = link.previous;
Link<ET> previous = link.next;
// 让link的前后节点进行链接,然后删除link节点(gc)
next.next = previous;
previous.previous = next;
// 让link的后一个节点作为当前节点
link = previous;
list.size--;
list.modCount++;
expectedModCount++;
canRemove = false;
return;
}
throw new IllegalStateException();
}
throw new ConcurrentModificationException();
}
功能方法
add
// 指定位置添加节点
@Override
public void add(int location, E object) {
if (location >= 0 && location <= size) { // 确定location在有效范围之内
Link<E> link = voidLink; // 取得头节点
if (location < (size / 2)) { // 如果是在链表的前半段
for (int i = 0; i <= location; i++) {
link = link.next; // 不断循环,直到link指向location位置的link
}
} else { // 如果是在链表的后半段
for (int i = size; i > location; i--) {
link = link.previous; // 不断循环,直到link指向location位置的link
}
}
// 到这里,link已经是location位置上的link了
// 新建newLink,位置在location-1和location之间
Link<E> previous = link.previous;
Link<E> newLink = new Link<E>(object, previous, link);
// 让location-1链接到newLink
// 让location链接到newLink
previous.next = newLink;
link.previous = newLink;
// 至此,newLink正式插入到location位置节点之前!
size++;
modCount++;
} else {
throw new IndexOutOfBoundsException();
}
}
addLast
@Override
public boolean add(E object) {
return addLastImpl(object);
}
private boolean addLastImpl(E object) {
// 新建newLink在voidLink.previous和voidLink之间,并让newLink连接前后节点
Link<E> oldLast = voidLink.previous;
Link<E> newLink = new Link<E>(object, oldLast, voidLink);
// 让前后节点连接newLink
voidLink.previous = newLink;
oldLast.next = newLink;
size++;
modCount++;
return true;
}
addAll
// 将一个集合插入到链表中指定位置
@Override
public boolean addAll(int location, Collection<? extends E> collection) {
if (location < 0 || location > size) { // 确定添加位置的有效性
throw new IndexOutOfBoundsException();
}
int adding = collection.size(); // 要添加的集合元素个数
if (adding == 0) {
return false;
}
// 看看要添加的集合是否是LinkedList
Collection<? extends E> elements = (collection == this) ?
new ArrayList<E>(collection) : collection;
Link<E> previous = voidLink;
// 判断location在链表的前/后半段,因为LinkedList是双向链表,因此
// .next和.previous永远都是有效的。voidLink是头节点,由它开始.next或.previous
// 都没问题。最终previous会指向location位置的节点。
if (location < (size / 2)) {
for (int i = 0; i < location; i++) {
previous = previous.next;
}
} else {
for (int i = size; i >= location; i--) {
previous = previous.previous;
}
}
Link<E> next = previous.next;
for (E e : elements) {
// 不断循环从location节点.next开始,链接collection中的链表
Link<E> newLink = new Link<E>(e, previous, null);
previous.next = newLink;
previous = newLink;
}
// 将collection中的链表最后一个节点.next链接到"原location.next节点"
previous.next = next;
// 双向绑定
next.previous = previous;
// 最终连接完毕!
size += adding;
modCount++;
return true;
}
// 添加一个集合,位置:双向链表末尾(头部)
@Override
public boolean addAll(Collection<? extends E> collection) {
int adding = collection.size(); // 要添加的集合元素个数
if (adding == 0) {
return false;
}
// 看看要添加的集合是否是ArrayList
Collection<? extends E> elements = (collection == this) ?
new ArrayList<E>(collection) : collection;
Link<E> previous = voidLink.previous;
// 添加collection到LinkedList,添加位置从头节点.previous开始。
// 所以可以说将collection添加到链表尾部,也可以说添加到头部
// 毕竟这一个一个双向循环链表
for (E e : elements) {
Link<E> newLink = new Link<E>(e, previous, null);
previous.next = newLink;
previous = newLink;
}
// 双向绑定
previous.next = voidLink;
voidLink.previous = previous;
size += adding;
modCount++;
return true;
}
addFirst
public void addFirst(E object) {
addFirstImpl(object);
}
// 添加元素在头节点之后
private boolean addFirstImpl(E object) {
// 新建的节点在voidLink和voidLink.next之间
Link<E> oldFirst = voidLink.next;
Link<E> newLink = new Link<E>(object, voidLink, oldFirst);
// 双向绑定
voidLink.next = newLink;
oldFirst.previous = newLink;
size++;
modCount++;
return true;
}
clear
@Override
public void clear() {
if (size > 0) {
size = 0;
// 最关键的两句!
// 头节点.next 断掉 指向自己
// 头节点.previous 断掉 指向自己
// 中间一大段链表没人指向,会自动gc
voidLink.next = voidLink;
voidLink.previous = voidLink;
modCount++;
}
}
contains
@Override
public boolean contains(Object object) {
Link<E> link = voidLink.next;
if (object != null) {
while (link != voidLink) { // 如果==,说明压根没元素,只有头节点自己而已
if (object.equals(link.data)) { // 节点比较的是数据域
return true;
}
link = link.next; // 不断指向下一个节点
}
} else {
while (link != voidLink) { // 如果==,说明压根没元素,只有头节点自己而已
if (link.data == null) { // 节点比较的是数据域
return true;
}
link = link.next; // 不断指向下一个节点
}
}
return false;
}
get
@Override
public E get(int location) {
if (location >= 0 && location < size) { // 确定location在有效范围之内
Link<E> link = voidLink;
if (location < (size / 2)) { // 查找分前半段和后半段,可以提高效率
for (int i = 0; i <= location; i++) {
link = link.next;
}
} else {
for (int i = size; i > location; i--) {
link = link.previous;
}
}
// 最终找到location位置上的节点,返回其数据域
return link.data;
}
throw new IndexOutOfBoundsException();
}
getFirst
public E getFirst() {
return getFirstImpl();
}
// 获取第一个节点的数据
private E getFirstImpl() {
Link<E> first = voidLink.next;
if (first != voidLink) { // 头节点算第0个节点,要获取的是头节点.next(第1个节点)
return first.data; // 返回第1个节点的数据
}
throw new NoSuchElementException();
}
getLast
// 获取最后一个节点的数据
public E getLast() {
// 第0个节点的上一个节点就是最后一个节点
Link<E> last = voidLink.previous;
if (last != voidLink) { // 不是头节点就行
return last.data;
}
throw new NoSuchElementException();
}
indexOf
// 从前往后进行数据域的比较
@Override
public int indexOf(Object object) {
int pos = 0;
Link<E> link = voidLink.next;
if (object != null) {
while (link != voidLink) { // 从第1个节点开始遍历进行比较
if (object.equals(link.data)) {
return pos;
}
link = link.next;
pos++;
}
} else {
while (link != voidLink) { // 数据域是null也可以,所以也在比较之列
if (link.data == null) {
return pos;
}
link = link.next;
pos++;
}
}
return -1;
}
lastIndexOf
// 从后往前进行数据域的比较
@Override
public int lastIndexOf(Object object) {
int pos = size;
Link<E> link = voidLink.previous;
if (object != null) {
// indexOf从第1个节点开始往后比较,那么lastIndexOf就从最后一个节点开始
// 往前比较,而比较方式一样
while (link != voidLink) {
pos--;
if (object.equals(link.data)) {
return pos;
}
link = link.previous;
}
} else {
while (link != voidLink) {
pos--;
if (link.data == null) {
return pos;
}
link = link.previous;
}
}
return -1;
}
remove
@Override
public E remove(int location) {
if (location >= 0 && location < size) { // 确定location在有效范围之内
Link<E> link = voidLink;
if (location < (size / 2)) { // 分前半段和后半段查找,提高效率
for (int i = 0; i <= location; i++) {
link = link.next;
}
} else {
for (int i = size; i > location; i--) {
link = link.previous;
}
}
// 遍历完,link指向location位置的节点
// 让link的前后节点进行链接,然后删除link节点
Link<E> previous = link.previous;
Link<E> next = link.next;
previous.next = next;
next.previous = previous;
size--;
modCount++;
return link.data;
}
throw new IndexOutOfBoundsException();
}
removeFirst
public E removeFirst() {
return removeFirstImpl();
}
private E removeFirstImpl() {
Link<E> first = voidLink.next; // 先获取第1个节点
if (first != voidLink) { // 如果第1个节点不是头节点
// 让第1个节点的前后节点链接,然后删除第1个节点
Link<E> next = first.next;
voidLink.next = next;
next.previous = voidLink;
size--;
modCount++;
return first.data;
}
throw new NoSuchElementException();
}
removeLast
public E removeLast() {
return removeLastImpl();
}
private E removeLastImpl() {
Link<E> last = voidLink.previous; // 获取最后一个节点
if (last != voidLink) { // 如果最后一个节点不是头节点
// 让最后一个节点的前后节点相连,然后不再指向最后节点,自动被gc
Link<E> previous = last.previous;
voidLink.previous = previous;
previous.next = voidLink;
size--;
modCount++;
return last.data;
}
throw new NoSuchElementException();
}
peekLast
// 返回最后一个节点的数据
public E peekLast() {
Link<E> last = voidLink.previous;
return (last == voidLink) ? null : last.data;
}
pollFirst
// 返回第一个节点的数据并移除第一个节点
public E pollFirst() {
return (size == 0) ? null : removeFirstImpl();
}
pollLast
// 返回最后一个节点的数据并移除最后一个节点
public E pollLast() {
return (size == 0) ? null : removeLastImpl();
}
pop
// 返回第一个节点的数据并移除第一个节点
public E pop() {
return removeFirstImpl();
}
push
// 添加元素到链表的第一个位置
public void push(E e) {
addFirstImpl(e);
}
set
@Override
public E set(int location, E object) {
if (location >= 0 && location < size) { // 确定location在有效范围之内
Link<E> link = voidLink; // 获取头节点
if (location < (size / 2)) { // 分段查询
for (int i = 0; i <= location; i++) {
link = link.next;
}
} else {
for (int i = size; i > location; i--) {
link = link.previous;
}
}
// 遍历完毕,link此时指向location位置的节点
// 赋值数据域
E result = link.data;
link.data = object;
return result;
}
throw new IndexOutOfBoundsException();
}
poll
// 返回第一个节点的数据并移除第一个节点
public E poll() {
return size == 0 ? null : removeFirst();
}
remove
// 移除第1个节点并返回
public E remove() {
return removeFirstImpl();
}
offer
// 添加元素到链表的最后一个位置
public boolean offer(E o) {
return addLastImpl(o);
}
peek
// 返回第1个节点的数据
public E peek() {
return peekFirstImpl();
}
private E peekFirstImpl() {
Link<E> first = voidLink.next;
return first == voidLink ? null : first.data;
}
toArray
@Override
public Object[] toArray() {
int index = 0;
Object[] contents = new Object[size]; // 新建集合大小的数组
Link<E> link = voidLink.next; // 获取到第一个节点
while (link != voidLink) {
contents[index++] = link.data; // 不断循环将链表每个节点的数据赋值给数组
link = link.next;
}
return contents;
}