Java基礎之Collections框架List接口實現類LinkedList及其源碼分析
List和Deque接口的雙鏈接列表實現。 實現所有可選的列表操作,並允許所有元素(包括null)。
所有操作都執行雙鏈表所期望的操作。 索引到列表中的操作將從開頭或結尾遍歷列表,以更接近指定索引的位置爲準。
LinkedList簡單使用
List<String> linkedList = new LinkedList<String>();
//添加元素
linkedList.add("tony");
linkedList.add("shanghai");
System.out.println(linkedList.toString());
linkedList.add(1, "Hu Pudong");
System.out.println(linkedList.toString());
//移除元素
linkedList.remove("tony");
System.out.println(linkedList.toString());
//是否包含相關元素
System.out.println(linkedList.contains("shanghai"));
List<String> listemp = new ArrayList<String>();
listemp.add("tony");
listemp.add("nan ma tou");
//將指定集合中的元素添加到linkedList中
linkedList.addAll(listemp);
System.out.println(linkedList.toString());
LinkedList源碼分析
上面對LinkedList簡單使用,揭開添加,刪除,包含等操作的內幕。
實例屬性:
transient int size = 0; //鏈表的大小
transient Node<E> first; //指向第一個節點的指針
transient Node<E> last; //指向最後一個節點的指針
構造函數
/***
創建一個空的列表
*/
public LinkedList() {
}
/**
構造一個包含指定元素的列表集合,按集合的返回順序迭代器。
*/
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
添加元素
public boolean add(E e) {
linkLast(e);
return true;
}
//關聯添加的用戶
void linkLast(E e) {
//獲取最後一個元素
final Node<E> l = last;
//l上一個元素,E當前元素 因爲添加往後面追加,後面的元素爲null
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
//如果沒有最後一個元素,代表添加爲第一個
if (l == null)
first = newNode;
else
//設置最後一個元素的後面一個爲新的元素
l.next = newNode;
size++; //設置大小 + 1
modCount++;
}
//私有內部類 node,保存linkedList中的元素
private static class Node<E> {
E item;
Node<E> next; //下一個元素
Node<E> prev; //上一個元素
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
添加指定集合中的元素到linkedList中
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
進行addAll操作
public boolean addAll(int index, Collection<? extends E> c) {
//檢查索引的合法性,索引不能大於size和小於0
checkPositionIndex(index);
//將集合轉爲爲數組
Object[] a = c.toArray();
int numNew = a.length; //獲取集合的大小
if (numNew == 0)
return false;
Node<E> pred, succ;
//如果索引爲鏈表的大小,設置相應的node
if (index == size) {
succ = null;
pred = last;
} else {
succ = node(index); //進行二分查找的方式獲取node
pred = succ.prev; //獲取查找到node的上一個節點
}
//通過遍歷進行賦值
for (Object o : a) {
@SuppressWarnings("unchecked") E e = (E) o;
Node<E> newNode = new Node<>(pred, e, null);
//說明上一個元素爲空
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
//進行node賦值
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
size += numNew; //擴大鏈表的大小
modCount++;
return true;
}
檢索node:
Node<E> node(int index) {
//如果索引小於鏈表大小的二分之一
if (index < (size >> 1)) {
Node<E> x = first;
//從第一個元素開始遍歷,到索引的大小
for (int i = 0; i < index; i++)
x = x.next;
return x; //返回最後的值的下一個node
} else {
Node<E> x = last;
//如果大於的話,說明在鏈表的後半部分,後面開始遍歷
for (int i = size - 1; i > index; i--)
x = x.prev;
return x; //返回最後的前一個元素
}
}
移除元素操作
移除所有的元素
public void clear() {
// 將節點設置爲null,等待GC進行回收
//遍歷獲取一個一個的節點
for (Node<E> x = first; x != null; ) {
Node<E> next = x.next;
x.item = null;
x.next = null;
x.prev = null;
x = next;
}
first = last = null;
size = 0;
modCount++;
}
移除元素(第一個)
public E remove() {
return removeFirst();
}
public E removeFirst() {
final Node<E> f = first; //獲取第一個元素
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next; //將第一個元素設置爲它的下一個元素 進行刪除第一個node
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
移除元素(最後一個)
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
private E unlinkLast(Node<E> l) {
// assert l == last && l != null;
final E element = l.item;
final Node<E> prev = l.prev;
l.item = null;
l.prev = null; // help GC
last = prev; //將最後一個元素元素設置爲它的前一個元素 進行刪除最後一個node
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
查詢
//包含操作
public boolean contains(Object o) {
return indexOf(o) != -1;
}
public int indexOf(Object o) {
int index = 0;
if (o == null) {
//遍歷node節點進行操作 每一個node都包含前一個節點和下一個節點
for (Node<E> x = first; x != null; x = x.next) {
if (x.item == null)
return index;
index++;
}
} else {
for (Node<E> x = first; x != null; x = x.next) {
if (o.equals(x.item))
return index;
index++;
}
}
return -1; //查詢不到返回-1
}
設置值
public E set(int index, E element) {
checkElementIndex(index); //檢查元素的下標
Node<E> x = node(index); //進行二分查找進行下標索引,找到當前下標的node
E oldVal = x.item;
x.item = element;
return oldVal;
}
由於雙向鏈表的還實現了Deque,所以還有相關的Deque的方法。
//添加元素
public void push(E e) {
addFirst(e); //push是從頭進行添加
}
//移除元素
public E pop() {
return removeFirst(); //彈出元素,刪除第一個元素
}
//返回第一個元素,但是不刪除
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
//刪除第一個元素
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
還有一些隊列的方法。相關的還有很多方法如迭代,比較等。這裏會有一個迭代器爲降序迭代器。
降序迭代器
private class DescendingIterator implements Iterator<E> {
private final ListItr itr = new ListItr(size());
public boolean hasNext() {
return itr.hasPrevious();
}
public E next() {
return itr.previous();
}
public void remove() {
itr.remove();
}
}