首页 > 代码库 > LinkedList源码阅读

LinkedList源码阅读

Collection类结构

Collection接口下有三个子接口类型:ListSetQueue

java collection

LinkedList接口

LinkedList实现了ListDeque两种类型的接口,List接口就是顺序表,在上一节ArrayList中有介绍。

Deque是"double ended queue"缩写,代表一个线性的集合支持在两端插入和删除元素操作。Deque接口定义了通过两端头和尾访问元素的方法,包括插入、删除、检查等。每个方法存在两种形式:抛出异常如果失败、返回一个特定值(null或false等)。方法具体描述如下:

 First Element (Head)Last Element (Tail)
TypeThrows exceptionSpecial valueThrows exceptionSpecial value
InsertaddFirst(e)offerFirst(e)addLast(e)offerLast(e)
RemoveremoveFirst()pollFirst()removeLast()pollLast()
ExaminegetFirst()peekFirst()getLast()peekLast()

Deque扩展了Queue接口,因此看以看做是个FIFO先进先出队列,元素是在队列尾部添加,头部删除。QueueDeque中方法对应关系如下:

Queue MethodEquivalent Deque Method
add(e)addLast(e)
offer(e)offerLast(e)
remove()removeFirst()
poll()pollFirst()
element()getFirst()
peek()peekFirst()

Deque也可以当做LlIFO后进先出的栈,类似于集合类中的Stack。当用于栈时,元素从头部添加和删除,对应方法如下:

Stack MethodEquivalent Deque Method
push(e)addFirst(e)
pop()removeFirst()
peek()peekFirst()

LinkedList实现

类的定义

public class LinkedList<E>
    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;

LinkedList采用双向链表,定义了一个头结点,Entry代表链表一个节点,header不包含有意义值,即使链表为空也有一个头结点,实际是一个带头节点的双向链表。

 private static class Entry<E> {
    E element;
    Entry<E> next;
    Entry<E> previous;
}

方法

构造方法负责初始化头节点的next和previouse引用,都指向自己本身。

public LinkedList() {
    header.next = header.previous = header;
}

add方法,addBefore(e,entry)实现在entry前面插入元素

public boolean add(E e) {
    addBefore(e, header);  //尾部添加
    return true;
}
private Entry<E> addBefore(E e, Entry<E> entry) {
    Entry<E> newEntry = new Entry<E>(e, entry, entry.previous); 
    //newEntry->next=entry,newEntry->previous=entry->previous
    newEntry.previous.next = newEntry; //entry->previous->next = newEntry
    newEntry.next.previous = newEntry; //entry->previous = newEntry
    size++;
    modCount++;
    return newEntry;
}
public void add(int index, E element) {
    addBefore(element, (index==size ? header : entry(index)));
}
private Entry<E> 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;
}

get方法

public E get(int index) {
    return entry(index).element;
}
public E getFirst() {
    if (size==0)
        throw new NoSuchElementException();
    return header.next.element;
}

其他操作如remove等,不一一介绍,主要是涉及链表操作,注意该链表是带一个头结点。

迭代器的实现

支持单向和双向迭代器,默认都是调用内部类LinkedList$ListItr类实现

类定义

private class ListItr implements ListIterator<E> {
    private Entry<E> lastReturned = header; 
    private Entry<E> next; //当前遍历位置
    private int nextIndex; //当前index
    private int expectedModCount = modCount;
}

方法

ListItr(int index) {
    if (index < 0 || index > size)
    throw new IndexOutOfBoundsException("Index: "+index+
                        ", Size: "+size);
    if (index < (size >> 1)) { //前半部分查找
        next = header.next;
    	for (nextIndex=0; nextIndex<index; nextIndex++)
        	next = next.next;
    } else {
        next = header;
   	for (nextIndex=size; nextIndex>index; nextIndex--)
        	next = next.previous;
    }
}

public boolean hasNext() {
    return nextIndex != size;
}

public E next() {
    checkForComodification();
    if (nextIndex == size)
        throw new NoSuchElementException();
    lastReturned = next;
    next = next.next;
    nextIndex++;
    return lastReturned.element;
}

public boolean hasPrevious() {
    return nextIndex != 0;
}

public E previous() {
    if (nextIndex == 0)
        throw new NoSuchElementException();
    lastReturned = next = next.previous;
    nextIndex--;
    checkForComodification();
    return lastReturned.element;
}

ArrayList中的迭代器实现类似,通过内部类直接访问外部类的成员和方法实现遍历操作,不过由于采用链表方式,多了一个next指向链表遍历位置的引用元素。

总结

  1. LinkedList实现了ListDeque接口,其中Deque是一个双端队列,可以在头部和尾部两端添加和删除元素,因此LinkedList既可以当作先进先出的队列,也可以当作后进先出的栈。
  2. LinkedList采用双向链表方式实现,因此插入、删除元素效率比较高,但不支持随机访问。
  3. 多线程环境下LinkedList不能保证线程安全,因此对其结构修改的操作应当程序员来保证线程安全,其迭代器支持fail-fast,迭代过程中试图发现是否发生修改,若修改了容器则抛出ConcurrentModificationException

LinkedList源码阅读