LinkedList的实现其实是一个带哑头节点的双向循环链表。
1.LinkedList的字段
private transient Entry<E> header = new Entry<E>(null, null, null);
//Entry是一个LinkedList的内部类,其实就是链表上的节点,包含两个指针,一个指向
//前面节点,一个指向后面节点
private static class Entry<E> {
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;
}
}
//LinkedList中元素的数量
private transient int size = 0;
最后还有一个继承来的modCount字段。
2.构造方法
/**
* 默认设置哑头节点,其next和previous引用都指向它自己。形成了循环链表
*/
public LinkedList() {
header.next = header.previous = header;
}
3.核心方法:
(1) addBefore方法
//在指定节点前面增加一个节点
private Entry<E> addBefore(E e, Entry<E> entry) {
//首先构建一个新的Entry节点,其next引用指向指定的节点entry,其
//previous引用指定节点原来的前面的节点
Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
//调整newEntry的前面节点的next引用指向newEntry
newEntry.previous.next = newEntry;
//调整newEntry的后面节点的previous引用指向newEntry
newEntry.next.previous = newEntry;
size++;
modCount++;
return newEntry;
}
(2)entry方法
/**
* 得到执行索引位置的节点,如果索引位置在前一半,则从前面开始查找,
若索引位置在后一半,则从后面位置开始查找。
*/
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)) { //size>>1等效于size/2,但是移位运算
//效率更高
for (int i = 0; i <= index; i++)
e = e.next;
} else {
for (int i = size; i > index; i--)
e = e.previous;
}
return e;
}
4.有了上面的两个核心方法,增加和删除的方法主要以这两个方法为基础的。
例如,
(1)
public void add(int index, E element) {
//如果在最后增加一个元素,就指定的节点就是哑头节点,由于是循环链表,
//在最后增加一个元素,它的后面的元素当然是头节点了。如果索引位置不是
//在最后,则先用entry方法得到指定索引位置的元素。之后再调用addBefore
//方法。
addBefore(element, (index==size ? header : entry(index)));
}
(2)
//删除指定索引位置的元素,也是先调用entry方法得到相应的元素,再进行删除操作。
public E remove(int index) {
return remove(entry(index));
}
private E remove(Entry<E> e) {
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;
}
5.其他方法
(1)
//删除一个对象,分对应的引用o是null还是非null两种情况。
public boolean remove(Object o) {
if (o==null) {
for (Entry<E> e = header.next; e != header; e = e.next) {
if (e.element==null) {
remove(e);
return true;
}
}
} else {
for (Entry<E> e = header.next; e != header; e = e.next) {
if (o.equals(e.element)) {
remove(e);
return true;
}
}
}
return false;
}
(2)
//查找元素o,也是分o为null和非null两种情况,但是不管是哪一种情况,都是顺序查找
public int indexOf(Object o) {
int index = 0;
if (o==null) {
for (Entry e = header.next; e != header; e = e.next) {
if (e.element==null)
return index;
index++;
}
} else {
for (Entry e = header.next; e != header; e = e.next) {
if (o.equals(e.element))
return index;
index++;
}
}
return -1;
}
6. 由于LinkedList实现了双端队列Deque这个接口,因此,也具有双端队列操作的相关方法。因此,LinkedList可以当作先进先出的队列使用,也可以当作先进后出的堆栈使用。
7. LinkedList实现了迭代器
但是,这个迭代器的是实现ListIterator接口的,也就是说,可以向前或者向后进行迭代。
Come from:http://jimmee.javaeye.com/blog/607891