LinkedList源码分析
1.链表介绍
链表是一种物理存储单元上非连续、非顺序的存储结构,数组元素的逻辑顺序是通过链表中的指针连接次序实现的。链表由一系列节点(链表中每一个元素都称为节点)组成,节点可以在运行时动态生成。每一个节点都包括两部分:一个是存储数据元素的数据域、另一个是存储下一个节点地址的指针域。
双向链表是链表的一种,由节点组成,每一个数据节点中都有两个指针,分别指向直接后继和直接前驱。
2.LinkedList的底层实现
LinkedList是基于双向链表实现的;
源码
1.构造方法
/**
* 空参构造方法
*/
public LinkedList() {
}
/**
* 带参构造方法
*
* @param c
*/
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
/**
* 将集合中的所有元素追加到此列表未部
* @param c
* @return
*/
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
插入方法
add(E e)
方法
/**
* 在链表的尾部添加一个新的节点
*/
public boolean add(E e) {
linkLast(e);
return true;
}
/**
* 链表中e作为最后一个元素
*
* Links e as last element.
*/
void linkLast(E e) {
//前继节点
final Node<E> l = last;
//新节点
// newNode = (l,e,null) ==> newNode = (前继节点,新创建的节,未部节点)
final Node<E> newNode = new Node<>(l, e, null);
//将原来的前继节替换成当前的新节点(设置新节点为尾节点)
last = newNode;
//判断指向最后一个节点的指针是否null
//如果为null,说明链表中没有元素节点;那么现在这个链表的头节点和为节点是新创建的节点
if (l == null)
first = newNode;
//如果不为null;设置原继节点的后继节点为新创建的节点
else
l.next = newNode;
//集合的长度加一
size++;
//链表被修改的次数加一
modCount++;
}
add(int index, E element)
方法
/**
* 向指定位置新增一个新的节点
*/
public void add(int index, E element) {
//检查index是否合法
checkPositionIndex(index);
//判断index是不是尾部节点,如果是直接插入到该位置(链表的尾部)
if (index == size)
linkLast(element);
else
//element 要插入的元素
//node(index) 原先的元素的节点
linkBefore(element, node(index));
}
/**
* 向链表的尾部插入一个元素
*/
void linkLast(E e) {
//前继节点
final Node<E> l = last;
//新节点
// newNode = (l,e,null) ==> newNode = (前继节点,新创建的节,未部节点)
final Node<E> newNode = new Node<>(l, e, null);
//将原来的前继节替换成当前的新节点(设置新节点为尾节点)
last = newNode;
//判断指向最后一个节点的指针是否null
//如果为null,说明链表中没有元素节点;那么现在这个链表的头节点和为节点是新创建的节点
if (l == null)
first = newNode;
//如果不为null;设置原继节点的后继节点为新创建的节点
else
l.next = newNode;
//集合的长度加一
size++;
//链表被修改的次数加一
modCount++;
}
/**
* 在链表的指定位置之间插入一个元素
*/
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
//获取当前索引位置节点的前继节点(原先元素的前继节点)
final Node<E> pred = succ.prev;
// newNode = pred <-- e --> succ
/**
* 这段代码什么意思,比方说:我现在的linked集合中有这些元素{1,2,3}
* 我现在向index=1的位置插入一个元素8,得到的结果是{1,8,2,3};
* 那么它做的事情就是先获取index=1元素的前继节点
* 接着就是创建新的节点,这个新的节点的位置就是:index索引的前继节点、新的节点、index索引所在的节点
* pred <-- e --> succ
*/
final Node<E> newNode = new Node<>(pred, e, succ);
//原先元素的前继节点就是当前插入元素的节点(修改原节点的前继节点为新创建的节点)
succ.prev = newNode;
//如果原先元素的前继节点为null,很显然它是在链表的头部插入元素了,那么开始节点就等于这个新创建的节点
if (pred == null)
first = newNode;
//不等于null,原先元素的前继节点的后继节点就等于新创建的节点
else
pred.next = newNode;
//链表的长度加 +1
size++;
//链表被修改的次数 +1
modCount++;
}
addFirst(E e)
/**
* 将指定的元素插入到此列表的开头。
* Inserts the specified element at the beginning of this list.
*
* @param e the element to add 要添加的元素
*/
public void addFirst(E e) {
linkFirst(e);
}
/**
* 链接e作为第一个元素。
* Links e as first element.
*/
private void linkFirst(E e) {
//头节点
final Node<E> f = first;
//新节点,新节点的直接前驱为null(因为它是新的头节点),直接后继为原头节点
final Node<E> newNode = new Node<>(null, e, f);
//头节点等于新节点
first = newNode;
//如果头节点为null,那么当前这个链表中是没有节点的,添加的节点就是链表中的第一个节点
//那么尾节点也是新创建的节点
if (f == null)
last = newNode;
else
//头节点不为null,原头节点的直接前驱指针指向新的节点(当前的头节点)
f.prev = newNode;
//链表的长度 +1
size++;
//链表被修改的次数+1
modCount++;
}
addLast(E e)
方法
/**
* 将指定的元素追加到此列表的末尾。
* Appends the specified element to the end of this list.
*
* <p>This method is equivalent to {@link #add}. 这个方法相当于add(E e)
*
* @param e the element to add 要添加的元素
*/
public void addLast(E e) {
linkLast(e);
}
/**
* 链表中e作为最后一个元素
*
* Links e as last element.
*/
void linkLast(E e) {
//前继节点
final Node<E> l = last;
//新节点
// newNode = (l,e,null) ==> newNode = (前继节点,新创建的节,未部节点)
final Node<E> newNode = new Node<>(l, e, null);
//将原来的前继节替换成当前的新节点(设置新节点为尾节点)
last = newNode;
//判断指向最后一个节点的指针是否null
//如果为null,说明链表中没有元素节点;那么现在这个链表的头节点和为节点是新创建的节点
if (l == null)
first = newNode;
//如果不为null;设置原继节点的后继节点为新创建的节点
else
l.next = newNode;
//集合的长度加一
size++;
//链表被修改的次数加一
modCount++;
}
删除方法
remove()
方法
/**
* 该方法的目的就是断开头节点,让头节点的后继节点取代头节点
*/
public E remove() {
return removeFirst();
}
public E removeFirst() {
//获取头节点
final Node<E> f = first;
//判断头节点是否为空
//如果为空抛出`没有这样的元素异常`程序终止运行
//不为空则调用unlinkFirst(f)方法移除头节点
if (f == null)
throw new NoSuchElementException();
return 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;
//如果头节点的后继节点为null,说明这个链表中只有这么一个数据。那么头节点后尾节点都为null
if (next == null)
last = null;
//头节点的后继节点不为null,则原头节点至为null
else
next.prev = null;
//链表长度 -1
size--;
//链表被修改的次数 + 1
modCount++;
//返回被移除的元素值
return element;
}
remove(Object o)
方法
/**
* 断开指定元素所在的节点
*/
public boolean remove(Object o) {
//判断方法传入的值是否为null
//如果为null遍历链表找到为元素null的节点,调用 unlink(x) 方法断开节点并将该节点的元素值至为null
//方法传入的值不为null,和为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;
}
/**
* 断开非空节点x的链接
* Unlinks non-null node x.
*/
E unlink(Node<E> x) {
// assert x != null;
//获取该x节点的元素值
final E element = x.item;
//获取x节点的后继节点
final Node<E> next = x.next;
//获取x节点的前继节点
final Node<E> prev = x.prev;
//判断x节点的前继节点是否为null,如果为null,则说明需要断开的节点就是头节点
//那么,新的头节点就是x节点的后节点
if (prev == null) {
first = next;
//x节点的前继节点不为null,就将x节点的前继节点指针指向x节点的后继节点,然后再断开x节点
} else {
prev.next = next;
x.prev = null;
}
//如果x节点的后继节点为null,则说明要断开的节点就是尾节点
//那么新的尾节点就是x节点的前至节点
if (next == null) {
last = prev;
//x节点的后继节点不为null,则将x节点的后继节点的指针指向x节点的前继节点,然后断开x节点,此时已经完成移除操作
} else {
next.prev = prev;
x.next = null;
}
//将x节点的元素值至为null
x.item = null;
//链表的长度 -1
size--;
//链表被修改的次数 + 1
modCount++;
//将移除的元素值返回
return element;
}
remove(int index)
方法
/**
* 断开指定位置下的节点
*/
public E remove(int index) {
//检查index是否合法
checkElementIndex(index);
//node(index) 获取index位置元素
return unlink(node(index));
}
/**
* 返回指定元素索引处的(非空)节点。
*/
Node<E> node(int index) {
// assert isElementIndex(index);
//判断index 小于元素size/2
//从前往后找
if (index < (size >> 1)) {
//获取头节点
Node<E> x = first;
//循环取到index位置的节点
for (int i = 0; i < index; i++)
x = x.next;
return x;
//从后往前找
} else {
//获取尾节点
Node<E> x = last;
//循环取到index位置的节点
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
/**
* 断开非空节点x的链接。
* Unlinks non-null node x.
*/
E unlink(Node<E> x) {
// assert x != null;
//获取x节点下的元素值
final E element = x.item;
//获取x节点的后继节点
final Node<E> next = x.next;
//获取x节点的前继节点
final Node<E> prev = x.prev;
//判断x节点的前继节点是否为null,如果为null说明要断开的节点就是头节点
//那么新的头节点就是原头节点(x)的后继节点
if (prev == null) {
first = next;
//x节点的前继节点不为null,则将x节点的前继节点的指针指向x节点的后继指针
//并断开x节点的前继节点指向x节点的指针
} else {
prev.next = next;
x.prev = null;
}
//判断x节点的后继节点是否为null,如果为null说明要断开的节点就是尾节点
//那么新的尾节点就是原尾节点(x)的前继节点
if (next == null) {
last = prev;
} else {
//x节点的后继节点不等于null,则将x节点的后继节点指针指向x节点的前继节点
//断开x节点的后继节点指向x节点的指针,x节点的直接前驱指针和直接后继指针都已经断开了即x节点已经断开
next.prev = prev;
x.next = null;
}
//将x节点的元素值置为null
x.item = null;
//链表的长度 -1
size--;
//链表被修改的次数 +1
modCount++;
//将移除的元素返回
return element;
}
查找方法
get(int index)
/**
* 返回列表中指定位置的元素
* Returns the element at the specified position in this list.
*
* @param index index of the element to return 要返回的元素的索引
* @return the element at the specified position in this list 元素位于此列表中的指定位置
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
//检查index是否合法(检查索引是否越界,如果越界抛出`索引越界异常`)
checkElementIndex(index);
// 返回该节点的元素值
return node(index).item;
}
/**
* 返回指定元素索引处的(非空)节点。
* Returns the (non-null) Node at the specified element index.
*/
Node<E> node(int index) {
// assert isElementIndex(index);
//判断index 是否小于(size/2)
//如果小于从前往后找
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;
}
}
遍历(Iterator)
/**
* Returns an iterator over the elements in this list (in proper
* sequence). 在列表中的元素上返回一个迭代器(以适当的顺序)
*
* This implementation merely returns a list iterator over the list.
* 此实现仅返回列表迭代器
*
* @return an iterator over the elements in this list (in proper sequence) 对列表中的元素返回一个迭代器(以适当的顺序)
*/
public Iterator<E> iterator() {
return listIterator();
}
public ListIterator<E> listIterator() {
return listIterator(0);
}
public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);
return new ListItr(index);
}
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
cursor = index;
}
public boolean hasPrevious() {
return cursor != 0;
}
public E previous() {
checkForComodification();
try {
int i = cursor - 1;
E previous = get(i);
lastRet = cursor = i;
return previous;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor-1;
}
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.set(lastRet, e);
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
AbstractList.this.add(i, e);
lastRet = -1;
cursor = i + 1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
private class Itr implements Iterator<E> {
/**
* 元素的索引,由后续对next的调用返回。
*/
int cursor = 0;
/**
* 最近一次调用next或previous返回的元素的索引。如果通过调用remove删除此元素,则重置为-1。
*/
int lastRet = -1;
/**
* 迭代器认为支持列表应该具有的mod计数值。如果违背了这个期望,迭代器就会检测到并发修改。
*/
int expectedModCount = modCount;
/**
* 判断是否下一个迭代元素
*/
public boolean hasNext() {
return cursor != size();
}
/**
* 获取元素的值
*/
public E next() {
checkForComodification();
try {
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
public interface Iterator<E> {
/**
* Returns {@code true} if the iteration has more elements.
* (In other words, returns {@code true} if {@link #next} would
* return an element rather than throwing an exception.)
*
* @return {@code true} if the iteration has more elements
*/
boolean hasNext();
/**
* Returns the next element in the iteration.
*
* @return the next element in the iteration
* @throws NoSuchElementException if the iteration has no more elements
*/
E next();
/**
* Removes from the underlying collection the last element returned
* by this iterator (optional operation). This method can be called
* only once per call to {@link #next}. The behavior of an iterator
* is unspecified if the underlying collection is modified while the
* iteration is in progress in any way other than by calling this
* method.
*
* @implSpec
* The default implementation throws an instance of
* {@link UnsupportedOperationException} and performs no other action.
*
* @throws UnsupportedOperationException if the {@code remove}
* operation is not supported by this iterator
*
* @throws IllegalStateException if the {@code next} method has not
* yet been called, or the {@code remove} method has already
* been called after the last call to the {@code next}
* method
*/
default void remove() {
throw new UnsupportedOperationException("remove");
}
/**
* Performs the given action for each remaining element until all elements
* have been processed or the action throws an exception. Actions are
* performed in the order of iteration, if that order is specified.
* Exceptions thrown by the action are relayed to the caller.
*/
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}