List

156 阅读27分钟
原文链接: blog.csdn.net

List笔录

 List相较于set、map,是按照一定顺序存储,List主要分为3类,ArrayList, LinkedList和Vector。以下是List的结构图,本文章重点讲解ArrayList与LinkedList的底层实现原理。


ArrayList

ArrayList采用了快速失败的机制,通过记录modCount参数来实现。在面对并发的修改时,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。

优点:随机访问元素

缺点:中间插入和移除元素速度较慢。
定义
[java] view plain copy print?
  1. public class ArrayList<E> extends AbstractList<E>   implements List<E>, RandomAccess, Cloneable, java.io.Serializable   
public class ArrayList<E> extends AbstractList<E>  implements List<E>, RandomAccess, Cloneable, java.io.Serializable 
 1.AbstractList提供了List接口的默认实现(个别方法为抽象方法)。
2.List接口定义了列表必须实现的方法。
3.RandomAccess是一个标记接口,接口内没有定义任何内容。
4. 实现了Cloneable接口的类,可以调用Object.clone方法返回该对象的浅拷贝。

5. 通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。序列化接口没有方法或字段,仅用于标识可序列化的语义。 

底层原理
1.底层使用数组实现
 有两个私有属性:
[java] view plain copy print?
  1. private transient Object[] elementData;   
private transient Object[] elementData; 
 (elementData存储内部元素,Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient)
[java] view plain copy print?
  1. private int size;   
private int size; 
(size存储元素数量)
2.构造方法:
1.构造一个默认初始容量为10的空列表。
[java] view plain copy print?
  1. public ArrayList() {  
  2.     this(10);  
  3. }   
public ArrayList() {
	this(10);
} 


 2.构造一个指定初始容量的空列表
[java] view plain copy print?
  1. public ArrayList(int initialCapacity) {    
  2.     super();    
  3.     if (initialCapacity < 0)    
  4.         throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);    
  5.     this.elementData = new Object[initialCapacity];    
  6. }   
public ArrayList(int initialCapacity) {  
	super();  
	if (initialCapacity < 0)  
		throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);  
	this.elementData = new Object[initialCapacity];  
} 

 3.构造一个包含指定collection的元素的列表,这些元素按照collection的迭代器返回它们的顺序排列。(返回若不是Object[]将调用Arrays.copyOf方法将其转为Object[])


[java] view plain copy print ?
  1. public ArrayList(Collection<? extends E> c) {  
  2.     elementData = c.toArray();  
  3.     size = elementData.length;  
  4.     // c.toArray might (incorrectly) not return Object[] (see 6260652)  
  5.     if (elementData.getClass() != Object[].class)  
  6.         elementData = Arrays.copyOf(elementData, size, Object[].class);  
  7. }  
public ArrayList(Collection<? extends E> c) {
	elementData = c.toArray();
	size = elementData.length;
	// c.toArray might (incorrectly) not return Object[] (see 6260652)
	if (elementData.getClass() != Object[].class)
		elementData = Arrays.copyOf(elementData, size, Object[].class);
}


 3.存储:

 ArrayList提供了set(int index, E element)、add(E e)、add(int index, E element)、addAll(Collection<? extends E> c)、addAll(int index, Collection<? extends E> c)这些添加元素的方法。

[java] view plain copy print?
  1. public boolean add(E e) {  
  2.     ensureCapacity(size + 1); // Increments modCount!!  
  3.     elementData[size++] = e;  
  4.     return true;  
  5. }  
public boolean add(E e) {
	ensureCapacity(size + 1); // Increments modCount!!
	elementData[size++] = e;
	return true;
}


 看到add(E e)中先调用了ensureCapacity(size+1)方法,之后将元素的索引赋给elementData[size],而后size自增。例如初次添加时,size为0,add将elementData[0]赋值为e,然后size设置为1(类似执行以下两条语句elementData[0]=e;size=1)。将元素的索引赋给elementData[size]不是会出现数组越界的情况吗?这里关键就在ensureCapacity(size+1)中了。
[java]view plain copy print?
  1. public void ensureCapacity(int minCapacity) {  
  2.     modCount++;  
  3.     int oldCapacity = elementData.length;  
  4.     if (minCapacity > oldCapacity) {  
  5.         Object oldData[] = elementData;  
  6.         int newCapacity = (oldCapacity * 3) /  2 + 1;  
  7.         if (newCapacity < minCapacity) {  
  8.             newCapacity = minCapacity;  
  9.         }  
  10.   
  11.         // minCapacity is usually close to size, so this is a win:  
  12.         elementData = Arrays.copyOf(elementData, newCapacity);  
  13.     }  
  14. }  
public void ensureCapacity(int minCapacity) {
	modCount++;
	int oldCapacity = elementData.length;
	if (minCapacity > oldCapacity) {
		Object oldData[] = elementData;
		int newCapacity = (oldCapacity * 3) / 2 + 1;
		if (newCapacity < minCapacity) {
			newCapacity = minCapacity;
		}

		// minCapacity is usually close to size, so this is a win:
		elementData = Arrays.copyOf(elementData, newCapacity);
	}
}

[java] view plain copy print?
  1. // 将指定的元素插入此列表中的指定位置。  
  2. // 如果当前位置有元素,则向右移动当前位于该位置的元素以及所有后续元素(将其索引加1)。  
  3. public void add(int index, E element) {  
  4.     if (index > size || index < 0)  
  5.         throw new IndexOutOfBoundsException("Index: " + index +  ", Size: "  
  6.                 + size);  
  7.     // 如果数组长度不足,将进行扩容。  
  8.     ensureCapacity(size + 1); // Increments modCount!!  
  9.     // 将 elementData中从Index位置开始、长度为size-index的元素,  
  10.     // 拷贝到从下标为index+1位置开始的新的elementData数组中。  
  11.     // 即将当前位于该位置的元素以及所有后续元素右移一个位置。  
  12.     System.arraycopy(elementData, index, elementData, index + 1, size  
  13.             - index);  
  14.     elementData[index] = element;  
  15.     size++;  
  16. }  
// 将指定的元素插入此列表中的指定位置。
// 如果当前位置有元素,则向右移动当前位于该位置的元素以及所有后续元素(将其索引加1)。
public void add(int index, E element) {
	if (index > size || index < 0)
		throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
				+ size);
	// 如果数组长度不足,将进行扩容。
	ensureCapacity(size + 1); // Increments modCount!!
	// 将 elementData中从Index位置开始、长度为size-index的元素,
	// 拷贝到从下标为index+1位置开始的新的elementData数组中。
	// 即将当前位于该位置的元素以及所有后续元素右移一个位置。
	System.arraycopy(elementData, index, elementData, index + 1, size
			- index);
	elementData[index] = element;
	size++;
}

[java] view plain copy print?
  1. public boolean addAll(Collection<? extends E> c) {  
  2.     Object[] a = c.toArray();  
  3.     int numNew = a.length;  
  4.     ensureCapacity(size + numNew); // Increments modCount  
  5.     System.arraycopy(a, 0, elementData, size, numNew);  
  6.     size += numNew;  
  7.     return numNew != 0;  
  8. }  
public boolean addAll(Collection<? extends E> c) {
	Object[] a = c.toArray();
	int numNew = a.length;
	ensureCapacity(size + numNew); // Increments modCount
	System.arraycopy(a, 0, elementData, size, numNew);
	size += numNew;
	return numNew != 0;
}


 先将集合c转换成数组,根据转换后数组的程度和ArrayList的size拓展容量,之后调用System.arraycopy方法复制元素到elementData的尾部,调整size。根据返回的内容分析,只要集合c的大小不为空,即转换后的数组长度不为0则返回true。
[java] view plain copy print?
  1. public boolean addAll(int index, Collection<?  extends E> c) {  
  2.     if (index > size || index < 0)  
  3.         throw new IndexOutOfBoundsException("Index: " + index +  ", Size: "  
  4.                 + size);  
  5.     Object[] a = c.toArray();  
  6.     int numNew = a.length;  
  7.     ensureCapacity(size + numNew); // Increments modCount  
  8.     int numMoved = size - index;  
  9.     if (numMoved > 0)  
  10.         System.arraycopy(elementData, index, elementData, index + numNew,  
  11.                 numMoved);  
  12.     System.arraycopy(a, 0, elementData, index, numNew);  
  13.     size += numNew;  
  14.     return numNew != 0;  
  15. }  
public boolean addAll(int index, Collection<? extends E> c) {
	if (index > size || index < 0)
		throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
				+ size);
	Object[] a = c.toArray();
	int numNew = a.length;
	ensureCapacity(size + numNew); // Increments modCount
	int numMoved = size - index;
	if (numMoved > 0)
		System.arraycopy(elementData, index, elementData, index + numNew,
				numMoved);
	System.arraycopy(a, 0, elementData, index, numNew);
	size += numNew;
	return numNew != 0;
}


 先判断index是否越界。其他内容与addAll(Collection<? extends E> c)基本一致,只是复制的时候先将index开始的元素向后移动X(c转为数组后的长度)个位置(也是一个复制的过程),之后将数组内容复制到elementData的index位置至index+X。 
[java] view plain copyprint?
  1. // 用指定的元素替代此列表中指定位置上的元素,并返回以前位于该位置上的元素。  
  2. public E set(int index, E element) {  
  3.     RangeCheck(index);  
  4.     E oldValue = (E) elementData[index];  
  5.     elementData[index] = element;  
  6.     return oldValue;  
  7. }   
// 用指定的元素替代此列表中指定位置上的元素,并返回以前位于该位置上的元素。
public E set(int index, E element) {
	RangeCheck(index);
	E oldValue = (E) elementData[index];
	elementData[index] = element;
	return oldValue;
} 

 
4.读取

[java] view plain copy print?
  1. // 返回此列表中指定位置上的元素。  
  2. public E get(int index) {  
  3.     RangeCheck(index);  
  4.     return (E) elementData[index];  
  5. }  
  6.   
  7. private void RangeCheck(int index) {  
  8.     if (index >= size)  
  9.         throw new IndexOutOfBoundsException("Index: " + index +  ", Size: "  
  10.                 + size);  
  11. }  
// 返回此列表中指定位置上的元素。
public E get(int index) {
	RangeCheck(index);
	return (E) elementData[index];
}

private void RangeCheck(int index) {
	if (index >= size)
		throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
				+ size);
}


5.删除
[java] view plain copy print?
  1. // 移除此列表中指定位置上的元素。  
  2. public E remove(int index) {  
  3.     RangeCheck(index);  
  4.     modCount++;  
  5.     E oldValue = (E) elementData[index];  
  6.     int numMoved = size - index - 1;  
  7.     if (numMoved > 0)  
  8.         System.arraycopy(elementData, index + 1, elementData, index,  
  9.                 numMoved);  
  10.     elementData[--size] = null; // Let gc do its work  
  11.     return oldValue;  
  12. }  
  13.   
  14. // 移除此列表中首次出现的指定元素(如果存在)。这是应为ArrayList中允许存放重复的元素。  
  15. public boolean remove(Object o) {  
  16.     // 由于ArrayList中允许存放null,因此下面通过两种情况来分别处理。  
  17.     if (o == null) {  
  18.         for (int index = 0; index < size; index++) {  
  19.             if (elementData[index] == null) {  
  20.                 // 类似remove(int index),移除列表中指定位置上的元素。  
  21.                 fastRemove(index);  
  22.                 return true;  
  23.             }  
  24.         }  
  25.     } else {  
  26.         for (int index = 0; index < size; index++) {  
  27.             if (o.equals(elementData[index])) {  
  28.                 fastRemove(index);  
  29.                 return true;  
  30.             }  
  31.         }  
  32.     }  
  33.     return false;  
  34. }  
// 移除此列表中指定位置上的元素。
public E remove(int index) {
	RangeCheck(index);
	modCount++;
	E oldValue = (E) elementData[index];
	int numMoved = size - index - 1;
	if (numMoved > 0)
		System.arraycopy(elementData, index + 1, elementData, index,
				numMoved);
	elementData[--size] = null; // Let gc do its work
	return oldValue;
}

// 移除此列表中首次出现的指定元素(如果存在)。这是应为ArrayList中允许存放重复的元素。
public boolean remove(Object o) {
	// 由于ArrayList中允许存放null,因此下面通过两种情况来分别处理。
	if (o == null) {
		for (int index = 0; index < size; index++) {
			if (elementData[index] == null) {
				// 类似remove(int index),移除列表中指定位置上的元素。
				fastRemove(index);
				return true;
			}
		}
	} else {
		for (int index = 0; index < size; index++) {
			if (o.equals(elementData[index])) {
				fastRemove(index);
				return true;
			}
		}
	}
	return false;
}

6.数据清除:
[java] view plain copy print?
  1. public void clear() {  
  2.     modCount++;  
  3.     // Let gc do its work  
  4.     for (int i = 0; i < size; i++) {  
  5.         elementData[i] = null;  
  6.     }  
  7.     size = 0;  
  8. }  
public void clear() {
	modCount++;
	// Let gc do its work
	for (int i = 0; i < size; i++) {
		elementData[i] = null;
	}
	size = 0;
}


7.数据复制:
[java] view plain copy print?
  1. public Object clone() {  
  2.     try {  
  3.         ArrayList<E> v = (ArrayList<E>) super.clone();  
  4.         v.elementData = Arrays.copyOf(elementData, size);  
  5.         v.modCount = 0;  
  6.         return v;  
  7.     } catch (CloneNotSupportedException e) {  
  8.         // this shouldn't happen, since we are Cloneable  
  9.         throw new InternalError();  
  10.     }  
  11. }  
public Object clone() {
	try {
		ArrayList<E> v = (ArrayList<E>) super.clone();
		v.elementData = Arrays.copyOf(elementData, size);
		v.modCount = 0;
		return v;
	} catch (CloneNotSupportedException e) {
		// this shouldn't happen, since we are Cloneable
		throw new InternalError();
	}
}


8.查找数据是否存在:
[java] view plain copy print?
  1. public boolean contains(Object o) {  
  2.     return indexOf(o) >= 0;  
  3. }  
public boolean contains(Object o) {
	return indexOf(o) >= 0;
}


9.查询数据坐标:
[java] view plain copy print?
  1. <span style="font-weight:normal;">public int indexOf(Object o) {  
  2.     if (o == null) {  
  3.         for (int i = 0; i < size; i++)  
  4.             if (elementData[i] == null)  
  5.                 return i;  
  6.     } else {  
  7.         for (int i = 0; i < size; i++)  
  8.             if (o.equals(elementData[i]))  
  9.                 return i;  
  10.     }  
  11.     return -1;  
  12. }</span>  
public int indexOf(Object o) {
	if (o == null) {
		for (int i = 0; i < size; i++)
			if (elementData[i] == null)
				return i;
	} else {
		for (int i = 0; i < size; i++)
			if (o.equals(elementData[i]))
				return i;
	}
	return -1;
}

10.转化为数组:
[java] view plain copy print?
  1. public Object[] toArray() {  
  2.     return Arrays.copyOf(elementData, size);  
  3. }  
public Object[] toArray() {
	return Arrays.copyOf(elementData, size);
}

11.
[java] view plain copy print?
  1. public void trimToSize() {  
  2.     modCount++;  
  3.     int oldCapacity = elementData.length;  
  4.     if (size < oldCapacity) {  
  5.         elementData = Arrays.copyOf(elementData, size);  
  6.     }  
  7. }  
public void trimToSize() {
	modCount++;
	int oldCapacity = elementData.length;
	if (size < oldCapacity) {
		elementData = Arrays.copyOf(elementData, size);
	}
}

将elementData的数组设置为ArrayList实际的容量,动态增长的多余容量被删除了。


LinkedList

优点:中间插入和移除元素代价比较小,优化了顺序访问,在Queue或者栈中应用
缺点:随机访问比较慢
定义:

[java] view plain copy print ?
  1. public class LinkedList<E>extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable  
public class LinkedList<E>extends AbstractSequentialList<E>implements List<E>, Deque<E>, Cloneable, java.io.Serializable
1.LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。
2.LinkedList 实现 List 接口,能对它进行队列操作。
3.LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。
4.LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
5.LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
6.LinkedList 是非同步的。
底层原理:LinkedList底层的数据结构是基于双向循环链表的,且头结点中不存放数据
 1.私有属性:

[java] view plain copy print?
  1. private transient Entry<E> header = new Entry<E>( null, null, null);   
  2.   
  3. private transient int size = 0;  
private transient Entry<E> header = new Entry<E>(null, null, null); 

private transient int size = 0;

以下是节点类Entry的实现:

[java] view plain copy print?
  1. private static class Entry<E> {  
  2.     E element;  
  3.     Entry<E> next;  
  4.     Entry<E> previous;  
  5.     Entry(E element, Entry<E> next, Entry<E> previous) {  
  6.         this.element = element;  
  7.         this.next = next;  
  8.         this.previous = previous;  
  9.     }  
  10. }  
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;
	}
}


next和previous分别表示该节点的下一个节点跟下一个节点。element是该节点包含的值
2.构造方法:
 第一个无参构造方法:
[java] view plain copy print?
  1. public LinkedList() {  
  2.     header.next = header.previous = header;  
  3. }  
public LinkedList() {
	header.next = header.previous = header;
}


第一个构造方法将header的next跟pervious都指向header,这就是一个双向循环链表的初始化;整个链表就是只有header一个结点,表现为空链表。
第二个接收一个Collection参数c:
[java] view plain copy print ?
  1. public LinkedList(Collection<? extends E> c) {  
  2.     this();  
  3.     addAll(c);  
  4. }  
public LinkedList(Collection<? extends E> c) {
	this();
	addAll(c);
}


先调用第一个构造方法,构造一个空的LinkedList,然后把c通过addAll方法加入进去。
3.增加元素
无论add的哪个实现都需要用到addBefore这个方法,这个方法是私有方法,无法直接从外部程序调用,若需要,只能通过反射。

[java] view plain copy print?
  1. private Entry<E> addBefore(E e, Entry<E> entry) {  
  2.     Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);  
  3.     newEntry.previous.next = newEntry;  
  4.     newEntry.next.previous = newEntry;  
  5.     size++;  
  6.     modCount++;  
  7.     return newEntry;  
  8. }  
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;
}


[java] view plain copy print?
  1. // 将元素(E)添加到LinkedList中  
  2. public boolean add(E e) {  
  3.     // 将节点(节点数据是e)添加到表头(header)之前。  
  4.     // 即,将节点添加到双向链表的末端。  
  5.     addBefore(e, header);  
  6.     return true;  
  7. }  
// 将元素(E)添加到LinkedList中
public boolean add(E e) {
	// 将节点(节点数据是e)添加到表头(header)之前。
	// 即,将节点添加到双向链表的末端。
	addBefore(e, header);
	return true;
}


传入的是结点数据e,调用addBefore,首先在addBefore()方法内创建一个新的节点newEntry,使newEntry的上一个结点是header.previous,也就是尾部节点,因为这是一个双向循环链表,下一个节点是header,因为新加入的节点需要作为尾节点,作为双向循环链表,尾节点的下一个指向header。因为是双向的,所以需要让周围的节点指向newEntry,然后增加size;
以下的实际增加过程跟上述描述差不多,都是调用了addBefore()方法。
    
[java] view plain copy print?
  1. public void add(int index, E element) {  
  2.     addBefore(element, (index == size ? header : entry(index)));  
  3. }  
  4.   
  5. public void addFirst(E e) {  
  6.     addBefore(e, header.next);  
  7. }  
  8.   
  9. public void addLast(E e) {  
  10.     addBefore(e, header);  
  11. }  
public void add(int index, E element) {
	addBefore(element, (index == size ? header : entry(index)));
}

public void addFirst(E e) {
	addBefore(e, header.next);
}

public void addLast(E e) {
	addBefore(e, header);
}


4.删除数据:
[java] view plain copy print?
  1. public E remove(int index) {  
  2.     Entry e = get(index);  
  3.     remove(e);  
  4.     return e.element;  
  5. }  
public E remove(int index) {
	Entry e = get(index);
	remove(e);
	return e.element;
}


 调用了remove()方法,这个方法同样是私有方法,这就是双向链表删除节点的实现。
    
[java] view plain copy print?
  1. private void remove(E e) {  
  2.     if (e == header)  
  3.         throw new NoSuchElementException();  
  4.     // 将前一节点的next引用赋值为e的下一节点  
  5.     e.previous.next = e.next;  
  6.     // 将e的下一节点的previous赋值为e的上一节点  
  7.     e.next.previous = e.previous;  
  8.     // 上面两条语句的执行已经导致了无法在链表中访问到e节点,而下面解除了e节点对前后节点的引用  
  9.     e.next = e.previous = null;  
  10.     // 将被移除的节点的内容设为null  
  11.     e.element = null;  
  12.     // 修改size大小  
  13.     size--;  
  14. }  
private void remove(E e) {
	if (e == header)
		throw new NoSuchElementException();
	// 将前一节点的next引用赋值为e的下一节点
	e.previous.next = e.next;
	// 将e的下一节点的previous赋值为e的上一节点
	e.next.previous = e.previous;
	// 上面两条语句的执行已经导致了无法在链表中访问到e节点,而下面解除了e节点对前后节点的引用
	e.next = e.previous = null;
	// 将被移除的节点的内容设为null
	e.element = null;
	// 修改size大小
	size--;
}


5.clear元素:
[java] view plain copy print?
  1. public void clear() {  
  2.     Entry<E> e = header.next;  
  3.     // e可以理解为一个移动的“指针”,因为是循环链表,所以回到header的时候说明已经没有节点了  
  4.     while (e != header) {  
  5.         // 保留e的下一个节点的引用  
  6.         Entry<E> next = e.next;  
  7.         // 解除节点e对前后节点的引用  
  8.         e.next = e.previous = null;  
  9.         // 将节点e的内容置空  
  10.         e.element = null;  
  11.         // 将e移动到下一个节点  
  12.         e = next;  
  13.     }  
  14.     // 将header构造成一个循环链表,同构造方法构造一个空的LinkedList  
  15.     header.next = header.previous = header;  
  16.     // 修改size  
  17.     size = 0;  
  18.     modCount++;  
  19. }  
public void clear() {
	Entry<E> e = header.next;
	// e可以理解为一个移动的“指针”,因为是循环链表,所以回到header的时候说明已经没有节点了
	while (e != header) {
		// 保留e的下一个节点的引用
		Entry<E> next = e.next;
		// 解除节点e对前后节点的引用
		e.next = e.previous = null;
		// 将节点e的内容置空
		e.element = null;
		// 将e移动到下一个节点
		e = next;
	}
	// 将header构造成一个循环链表,同构造方法构造一个空的LinkedList
	header.next = header.previous = header;
	// 修改size
	size = 0;
	modCount++;
}



6.获取数据:

[java] view plain copy print?
  1. public E get(int index) {  
  2.     return entry(index).element;  
  3. }  
  4.   
  5. // 获取双向链表中指定位置的节点  
  6. private Entry<E> entry(int index) {  
  7.     if (index < 0 || index >= size)  
  8.         throw new IndexOutOfBoundsException("Index: " + index +  ", Size: "  
  9.                 + size);  
  10.     Entry<E> e = header;  
  11.     // 获取index处的节点。  
  12.     // 若index < 双向链表长度的1/2(位运算),则从前先后查找;  
  13.     // 否则,从后向前查找。  
  14.     if (index < (size >> 1)) {  
  15.         for (int i = 0; i <= index; i++)  
  16.             e = e.next;  
  17.     } else {  
  18.         for (int i = size; i > index; i--)  
  19.             e = e.previous;  
  20.     }  
  21.     return e;  
  22. }  
public E get(int index) {
	return entry(index).element;
}

// 获取双向链表中指定位置的节点
private Entry<E> entry(int index) {
	if (index < 0 || index >= size)
		throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
				+ size);
	Entry<E> e = header;
	// 获取index处的节点。
	// 若index < 双向链表长度的1/2(位运算),则从前先后查找;
	// 否则,从后向前查找。
	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;
}


7.查询数据是否存在:
[java] view plain copy print?
  1. public boolean contains(Object o) {  
  2.     return indexOf(o) != -1;  
  3. }  
  4.   
  5. // 从前向后查找,返回“值为对象(o)的节点对应的索引” 不存在就返回-1  
  6. public int indexOf(Object o) {  
  7.     int index = 0;  
  8.     if (o == null) {  
  9.         for (Entry e = header.next; e != header; e = e.next) {  
  10.             if (e.element == null)  
  11.                 return index;  
  12.             index++;  
  13.         }  
  14.     } else {  
  15.         for (Entry e = header.next; e != header; e = e.next) {  
  16.             if (o.equals(e.element))  
  17.                 return index;  
  18.             index++;  
  19.         }  
  20.     }  
  21.     return -1;  
  22. }  
public boolean contains(Object o) {
	return indexOf(o) != -1;
}

// 从前向后查找,返回“值为对象(o)的节点对应的索引” 不存在就返回-1
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;
}


8.数据复制:
[java] view plain copy print?
  1. public Object clone() {  
  2.     LinkedList<E> clone = null;  
  3.     try {  
  4.         clone = (LinkedList<E>) super.clone();  
  5.     } catch (CloneNotSupportedException e) {  
  6.         throw new InternalError();  
  7.     }  
  8.     clone.header = new Entry<E>(null, null,  null);  
  9.     clone.header.next = clone.header.previous = clone.header;  
  10.     clone.size = 0;  
  11.     clone.modCount = 0;  
  12.     for (Entry<E> e = header.next; e != header; e = e.next)  
  13.         clone.add(e.element);  
  14.     return clone;  
  15. }  
public Object clone() {
	LinkedList<E> clone = null;
	try {
		clone = (LinkedList<E>) super.clone();
	} catch (CloneNotSupportedException e) {
		throw new InternalError();
	}
	clone.header = new Entry<E>(null, null, null);
	clone.header.next = clone.header.previous = clone.header;
	clone.size = 0;
	clone.modCount = 0;
	for (Entry<E> e = header.next; e != header; e = e.next)
		clone.add(e.element);
	return clone;
}


调用父类的clone()方法初始化对象链表clone,将clone构造成一个空的双向循环链表,之后将header的下一个节点开始将逐个节点添加到clone中。最后返回克隆的clone对象。


[java] view plain copy print ?
  1. public Object[] toArray() {  
  2.     Object[] result = new Object[size];  
  3.     int i = 0;  
  4.     for (Entry<E> e = header.next; e != header; e = e.next) {  
  5.         result[i++] = e.element;  
  6.     }  
  7.     return result;  
  8. }  
public Object[] toArray() {
	Object[] result = new Object[size];
	int i = 0;
	for (Entry<E> e = header.next; e != header; e = e.next) {
		result[i++] = e.element;
	}
	return result;
}

[java] view plain copy print?
  1. public <T> T[] toArray(T[] a) {  
  2.     // 先判断出入的数组a的大小是否足够,若大小不够则拓展。  
  3.     // 这里用到了发射的方法,重新实例化了一个大小为size的数组。  
  4.     // 之后将数组a赋值给数组result,遍历链表向result中添加的元素。  
  5.     // 最后判断数组a的长度是否大于size,若大于则将size位置的内容设置为null。返回a*/  
  6.     if (a.length < size) {  
  7.         a = (T[]) java.lang.reflect.Array.newInstance(a.getClass()  
  8.                 .getComponentType(), size);  
  9.     }  
  10.     int i = 0;  
  11.     Object[] result = a;  
  12.     for (Entry<E> e = header.next; e != header; e = e.next) {  
  13.         result[i++] = e.element;  
  14.     }  
  15.     if (a.length > size) {  
  16.         a[size] = null;  
  17.     }  
  18.     return a;  
  19. }  
public <T> T[] toArray(T[] a) {
	// 先判断出入的数组a的大小是否足够,若大小不够则拓展。
	// 这里用到了发射的方法,重新实例化了一个大小为size的数组。
	// 之后将数组a赋值给数组result,遍历链表向result中添加的元素。
	// 最后判断数组a的长度是否大于size,若大于则将size位置的内容设置为null。返回a*/
	if (a.length < size) {
		a = (T[]) java.lang.reflect.Array.newInstance(a.getClass()
				.getComponentType(), size);
	}
	int i = 0;
	Object[] result = a;
	for (Entry<E> e = header.next; e != header; e = e.next) {
		result[i++] = e.element;
	}
	if (a.length > size) {
		a[size] = null;
	}
	return a;
}