首先申明一下,此篇文章仅仅是我个人学习ArrayList源码后的学习总结,如果有错误,可以提出来探讨。
1.1 原理
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
private transient Entry<E> header = new Entry<E>(null, null, null);
private transient int size = 0;
E element;
Entry<E> next;
Entry<E> previous;
Entry(E element, Entry<E> next, Entry<E> previous) {
this.element = element;
this.next = next;
this.previous = previous;
}
}
从结构上讲,是通过双向链表的形式实现。其实最关键的是那个heade对象。它才是整个LinkedList的核心。它是连接链表的开始和结束的关键节点。通过它可以向前,向后操作。
1.2 核心方法(都是私有)
1.2.1 AddBefore()
这个方法是所有的插入方法的核心,包括所以的add方法(除了addAll()),所有offer方法
源码:
private Entry<E> addBefore(E e, Entry<E> entry) {
//创建链路的节点,除了自己本身,还包括前置节点,后置节点。
Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
//修改前一个节点的的后置节点指向它
newEntry.previous.next = newEntry;
//修改后一个节点的的前置节点指向它
newEntry.next.previous = newEntry;
size++;
modCount++;//用于线程安全。
return newEntry;
}
1.2.2 Entry(int index)
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+size);
Entry<E> e = header;
if (index < (size >> 1)) {
for (int i = 0; i <= index; i++)
e = e.next;
} else {
for (int i = size; i > index; i--)
e = e.previous;
}
return e;
}
此方法可以通过index获得对应的节点。主要用于方法参数中有index的方法,如get,remove;
从代码上看,通过index获得对应的节点,有两个方式,如果index在整条链路的前半截,那么是从前向后遍历,反之,从后往前遍历。
1.2.3 remove(Entry<e> entry)
if (e == header)
throw new NoSuchElementException();
E result = e.element;
e.previous.next = e.next;
e.next.previous = e.previous;
e.next = e.previous = null;
e.element = null;
size--;
modCount++;
return result;
}
此方法是删除操作的核心方法。主要用于删除方法,如:remove(int),remove(Object),
removeFirst(),removeLast();
1.3 迭代器
只提供一种迭代器(ListItr,不同于ArrayList的ListItr)
在ArrayList的Itr迭代器中,采用的维护cursor指向来遍历数组,而LinkedList是通过维护nextIndex和节点next来遍历链表。
通过参数index可以自定义遍历的开始位置(任意位置),
这个构造方法通过传入的index维护nextIndex指针和next节点,
public boolean hasNext() {
returnnextIndex != size;
}
public E next() {
checkForComodification();
if (nextIndex ==size)
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
returnlastReturned.element;
}
public boolean hasPrevious() {
returnnextIndex != 0;
}
public E previous() {
if (nextIndex == 0)
throw new NoSuchElementException();
lastReturned = next = next.previous;
nextIndex--;
checkForComodification();
returnlastReturned.element;
}
public int nextIndex() {
returnnextIndex;
}
public int previousIndex() {
returnnextIndex-1;
}
public void remove() {
checkForComodification();
Entry<E> lastNext = lastReturned.next;
try {
LinkedList.this.remove(lastReturned);
} catch (NoSuchElementException e) {
throw new IllegalStateException();
}
if (next==lastReturned)
next = lastNext;
else
nextIndex--;
lastReturned = header;
expectedModCount++;
}
public void set(E e) {
if (lastReturned ==header)
throw new IllegalStateException();
checkForComodification();
lastReturned.element = e;
}
public void add(E e) {
checkForComodification();
lastReturned = header;
addBefore(e, next);
nextIndex++;
expectedModCount++;
}
final void checkForComodification() {
if (modCount !=expectedModCount)
throw new ConcurrentModificationException();
}
从源码上看,跟ArrayList的ListItr迭代器很类似,只是具体的实现有点差异。
2 ArrayList和LinkedList的总结
查询操作:ArrayList可以通过下标找到对应位置的值,效率高;而LinkedList需要向前或向后遍历才能找到对应的值,效率低。
插入和删除操作:ArrayList需要数据的迁移所以效率低。LinkedList需要查询到对应的节点,才能直接操作(不需要数据的迁移),相对来说,效率高。