LinkedList是一种可以在任何位置进行高效地插入和移除操作的有序序列,它是基于双向链表实现的。
1、继承结构
2、LinkedList数据结构
如上图所示,LinkedList底层使用的双向链表结构,有一个头结点和一个尾结点,双向链表意味着我们可以从头开始正向遍历,或者是从尾开始逆向遍历,并且可以针对头部和尾部进行相应的操作。
3、源码分析
3.1、AbstractSequentialList实现
与ArrayList相比,LinkedList还实现了Deque接口并且继承于AbstractSequentialList类。这个类与AbstractList类相反,它实现了“随机访问”方法get(int index), set(int index, E element), add(int index, E element) 和 remove(int index)基于List的迭代器之上,因此它的随机访问是以遍历的形式实现的。
3.1.1、get方法
public E get(int index) {
try {
return listIterator(index).next();
} catch (NoSuchElementException exc) {
throw new IndexOutOfBoundsException("Index: "+index);
}
}
可以看到get方式只是提供了随机访问的方法调用形式,底层是通过使用迭代器遍历的形式实现的,listIterator是个抽象方法,由LinkedList实现。
3.1.2、set方法
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);
}
}
set方法与get方法类似,使用迭代器遍历到index指定的节点然后替换。
3.1.3、remove方法
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);
}
}
核心逻辑还是使用listIterator返回的迭代器的删除操作。
3.2、LinkedList核心方法实现
上面提到AbstractSequentialList的伪随机访问都是基于listIterator返回的迭代器实现的,下面就先看一下listIterator方法在LinkedList的实现原理。
3.2.1、listIterator方法
public ListIterator<E> listIterator(int index) {
// 检测角标越界
checkPositionIndex(index);
return new ListItr(index);
}
ListItr是LinkedList的私有内部类,Node 含有上下两个节点的引用,在下面代码可以看出实现随机访问的形式是以链表遍历的方式实现的。
private class ListItr implements ListIterator<E> {
private Node<E> lastReturned;
private Node<E> next;
private int nextIndex;
private int expectedModCount = modCount;
ListItr(int index) {
// assert isPositionIndex(index);
next = (index == size) ? null : node(index);
nextIndex = index;
}
public boolean hasNext() {
return nextIndex < size;
}
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}
public boolean hasPrevious() {
return nextIndex > 0;
}
public E previous() {
checkForComodification();
if (!hasPrevious())
throw new NoSuchElementException();
lastReturned = next = (next == null) ? last : next.prev;
nextIndex--;
return lastReturned.item;
}
public int nextIndex() {
return nextIndex;
}
public int previousIndex() {
return nextIndex - 1;
}
public void remove() {
checkForComodification();
if (lastReturned == null)
throw new IllegalStateException();
Node<E> lastNext = lastReturned.next;
unlink(lastReturned);
if (next == lastReturned)
next = lastNext;
else
nextIndex--;
lastReturned = null;
expectedModCount++;
}
public void set(E e) {
if (lastReturned == null)
throw new IllegalStateException();
checkForComodification();
lastReturned.item = e;
}
public void add(E e) {
checkForComodification();
lastReturned = null;
if (next == null)
linkLast(e);
else
linkBefore(e, next);
nextIndex++;
expectedModCount++;
}
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (modCount == expectedModCount && nextIndex < size) {
action.accept(next.item);
lastReturned = next;
next = next.next;
nextIndex++;
}
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}