LinkedList类继承自AbstractSequentialList类,并且实现了List, Deque Cloneable, java.io.Serializable接口,因此,LinkedList不仅可以作为单列集合来使用(适合应用于频繁修改集合内容、多写少读的场景),还可以作为队列(双端队列,因为它实现的是Deque接口)、栈来使用,此外LinkedList还可以被克隆和序列化传输。
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
由于LinkedList的底层实现结构是双向链表,因此它定义了两个Node对象——头节点和尾节点,并且使用size变量来记录双向链表的长度。
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
在LinkedList源码中,除了一些有关结构的定义也定义了很多方法,包括一些通用的常用方法以及针对具体的实现对象而创建的一些方法。
方法名 | 参数列表 | 返回值类型 | 作用 |
add() | E e | boolean | 向链表中添加元素(默认添加在尾节点后) |
add() | int index, E element | 向链表中的指定位置添加元素 | |
addFirst() | E e | 向链表的头部添加元素 | |
addLast() | E e | 向链表的尾部添加元素 | |
addAll() | Collection<? extends E> c | boolean | 将一个单列集合中的所有元素添加到链表中 |
addAll() | int index, Collection<? extends E> c | boolean | 将一个单列集合中的所有元素添加到链表的指定位置中 |
get() | int index | E(泛型) | 获取链表中指定下标的元素 |
getFirst() | E | 获取链表中的头元素 | |
getLast() | E | 获取链表中的尾元素 | |
indexOf() | Object o | int | 查找链表中指定下标元素的位置,如果不存在则返回-1 |
remove() | E | 删除列表中的元素(默认删除头元素) | |
remove() | Object o | boolean | 删除指定内容的元素 |
remove() | int index | E | 删除指定位置的元素 |
removeFirst() | E | 删除链表的头元素 | |
removeLast() | E | 删除链表的尾元素 | |
clear() | 清空列表中的所有元素 | ||
size() | int | 获取链表的长度 | |
sort() | Comparator c | (默认方法)根据Comparator比较器对列表元素进行排序 | |
toArray() | T[] a | T[] (泛型数组) | 将链表转换成数组 |
由于LinkedList中的方法繁多,但实现结果类似,因此我将对部分方法的代码逻辑表述我的理解。
1.增添元素
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
// 获取当前的尾节点存放在l中
final Node<E> l = last;
// 把新节点e作为当前节点
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
// 如果原尾节点为空,则表示链表为空,新的尾节点也是头节点
if (l == null)
first = newNode;
// 如果原尾节点不为空,即链表不为空,则e为新的尾节点
else
l.next = newNode;
// 链表长度加一
size++;
modCount++;
}
2.删除元素
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 {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
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;
//若当前节点的上一个节点为null,则设当前节点的下一个节点为头节点
if (prev == null) {
first = next;
//若不为null,则当前节点为下一个节点,当前节点的上一个节点设为null
} else {
prev.next = next;
x.prev = null;
}
//若当前节点的下一个节点为null,即当前节点为尾节点,则设当前节点的上一个节点为尾节点
if (next == null) {
last = prev;
//否则,当前节点为上一个节点,他的下一个节点为null
} else {
next.prev = prev;
x.next = null;
}
//x为null,链表长度减一,返回要素element
x.item = null;
size--;
modCount++;
return element;
}
3.查找元素
传入查找元素的下标,通过get()方法查询该位置的元素,在get()方法中调用了checkElementIndex()进行判别,如果下标范围< 0 或 >= size,则抛出索引越界异常。
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
private void checkElementIndex(int index) {
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private boolean isElementIndex(int index) {
return index >= 0 && index < size;
}
方法名 | 参数列表 | 返回值类型 | 作用 |
offer() | E e | boolean | 向队列中添加元素(默认添加在尾部) |
offerFirst() | E e | boolean | 向队列的首部添加元素 |
offerLast() | E e | boolean | 向队列的尾部添加元素 |
poll() | E | 删除队列中的元素(默认删除队头元素) | |
pollFirst() | E | 删除队头元素 | |
pollLast() | E | 删除队尾元素 | |
peek() | E | 获取队头元素 |
1.删除元素
public E poll() {
//将头节点存放在f节点
final Node<E> f = first;
//如果f为null,则返回null 如果不为null则调用unlinkFirst()方法
return (f == null) ? null : unlinkFirst(f);
}
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;
}
2.获取元素
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
方法名 | 参数列表 | 返回值类型 | 作用 |
push() | E e | 进栈 | |
pop() | E | 栈顶元素出栈 |
1.入栈
public void push(E e) {
addFirst(e);
}
2.出栈
public E pop() {
return removeFirst();
}