上次咱們分析了ArrayList,你們都已經瞭解了分析一個集合的步驟。那接下來,咱們繼續分析LinkedList。廢話不很少說,直接整。node
/**
* 指針指向第一個節點
* 初始化: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first;
/**
* 指針指向最後一個節點
* 初始化: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
複製代碼
從LinkedList成員中,能夠看出Lined內部有兩個指針,first(指向第一個節點)與Last(指向最後一個節點)。查看相關Node類聲明:安全
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;
}
}
複製代碼
Node類中,保存了當前數據元素,上一個節點,及下一個節點。從這裏,咱們大概瞭解到了LinkedList的內部結構是鏈表。bash
public boolean add(E e) {
linkLast(e);
return true;
}
複製代碼
add方法內部調用了linkLast(e),繼續走linkLast(e)。ui
void linkLast(E e) {
final Node<E> l = last;//last指向最後一個節點。
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;//frist指向第一個添加元素
else
l.next = newNode;//不是第一次添加,上一個節點的next指向當前節點
size++;
modCount++;
}
複製代碼
當該方法執行是,會初始化一個Node節點保存當前添加元素及上一個節點。若是是第一次執行,該方法,first與Last都會指向該節點。若是不是第一次執行。上個節點的next會指向新添加的節點,且last指向新添加的節點。this
addFist(e)中方法直接調用了linkFrist(e)方法,咱們直接查看LinkFirst方法:spa
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
複製代碼
linkFirst方法內部建立了一個新的節點。若是是第一次添加。新節點上個節點爲null。若是不是,則新的節點的上個的節點爲first原來指向的節點,first指向新添加的節點。線程
public E get(int index) {
checkElementIndex(index);//判斷是否操做存儲的長度
return node(index).item;
}
複製代碼
get方法先判斷時候在有效範圍類,若是調用了node(index)方法返回相應元素,繼續走node方法。3d
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
複製代碼
該方法內部先判斷index的位置是否小於總長度的一半,若是是,則從鏈表前方遍歷,若是不是,則從鏈表最末尾進行遍歷。指針
final Node<E> f = first;
if (f == null)//若是first沒有指向元素,拋出異常
throw new NoSuchElementException();
return unlinkFirst(f);
}
複製代碼
removeFirst()方法,先判斷當前frist時候爲null,若是不是,將first做爲參數傳入unLinkFirst()方法,查看unLinkFirst方法。code
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;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
複製代碼
unLinkFirst方法將器node中數據置爲null,且將frist節點,指向f的下一個節點。並將f的下一個節點的上個節點(也就是f)至爲null。
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
複製代碼
removeLast方法內把Last指向的節點,傳入unLikeLast()方法,繼續走unLinkLast方法。
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;
if (prev == null)
first = null;
else
prev.next = null;
size--;
modCount++;
return element;
}
複製代碼
unLinkLast方法內部獲取last重寫指向Last原節點的上一個節點,同時將Last原節點至爲null.
總結
最後,附上我寫的一個基於Kotlin 仿開眼的項目SimpleEyes(ps: 其實在我以前,已經有不少小朋友開始仿這款應用了,可是我以爲要作就作好。因此個人項目和其餘的人應該不一樣,不單單是簡單的一個應用。可是,可是。可是。重要的話說三遍。還在開發階段,不要打我),歡迎你們follow和start