LinkedList是對鏈表的擴展,其底層使用鏈表實現,不是線程安全的集合類。其繼承AbstractSequentialList,實現了List, Deque, Cloneable,Serializable各個接口,其中AbstractSequentialList繼承了AbstractList抽象類,AbstractList是對支持隨機讀取的List的部分功能的抽象,AbstractSequentialList是對不支持隨機讀取的List的一部分功能的抽象。而且LinkedList實現了Deque接口,表明其支持雙端隊列的全部功能。node
LinkedList首先是鏈表的擴展,而且實現了雙端隊列的接口,因此其特色以下:安全
//元素的個數 transient int size = 0; //首節點 transient Node<E> first; //尾節點 transient Node<E> last;
在此以前,先介紹一下雙端鏈表的數據結構數據結構
private static class Node<E> { //節點的值 E item; //下一個節點,若是爲尾節點,則此值爲null Node<E> next; //前一個節點,若是爲首節點,則此值爲null Node<E> prev; Node(Node<E> prev, E element, Node<E> next) { this.item = element; this.next = next; this.prev = prev; } }
//向鏈表頭添加元素 private void linkFirst(E e) { final Node<E> f = first; //設置新節點,令首節點等於新節點,並將新節點的next指向原來的首節點 final Node<E> newNode = new Node<>(null, e, f); first = newNode; //若是原來首節點爲空,表明爲空鏈表,則令尾節點也爲新節點 ,不然,令原來首節點的前一個節點爲新節點 if (f == null) last = newNode; else f.prev = newNode; //元素個數與修改次數進行增長 size++; modCount++; } //向鏈表尾添加元素 void linkLast(E e) { final Node<E> l = last; //設置新節點,令尾節點指向新節點,而且將新節點的prev指向原來的尾節點 final Node<E> newNode = new Node<>(l, e, null); last = newNode; //若是原來尾節點爲空,表明爲空鏈表,則令首節點也爲新節點 ,不然,令原來尾節點的下一個節點爲新節點 if (l == null) first = newNode; else l.next = newNode; size++; modCount++; } //在給定節點以前插入對應節點 void linkBefore(E e, Node<E> succ) { //獲取給定節點的前一個節點,設爲pred final Node<E> pred = succ.prev; //設置新節點,令其prev爲給定節點的前一個節點,next爲給定節點 final Node<E> newNode = new Node<>(pred, e, succ); //同時設置給定節點的前一個節點爲新節點 succ.prev = newNode; //判斷pred是否爲空,若是是,那麼新節點就是首節點 ,不然,直接令pred的下一個節點爲新節點 if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; } //刪除首節點 private E unlinkFirst(Node<E> f) { final E element = f.item; final Node<E> next = f.next; //將首節點中相關引用置空,防止內存泄漏 f.item = null; f.next = null; //令首節點爲首節點的下一個節點 first = next; //若是首節點爲空,那麼直接將尾節點也置空, 不然,將當前首節點的prev置爲null if (next == null) last = null; else next.prev = null; size--; modCount++; return element; } //刪除尾節點 private E unlinkLast(Node<E> l) { final E element = l.item; final Node<E> prev = l.prev; //將尾節點中相關引用置空,防止內存泄漏 l.item = null; l.prev = null; //令尾節點爲尾節點的前一個節點 last = prev; //若是尾節點爲空,那麼直接將首節點也置空, 不然,將當前尾節點的next置爲null if (prev == null) first = null; else prev.next = null; size--; modCount++; return element; } //刪除指定元素 E unlink(Node<E> x) { final E element = x.item; final Node<E> next = x.next; final Node<E> prev = x.prev; //若是指定節點的前一個節點爲空,表明制定節點爲首節點 ,令首節點爲指定節點的下一個節點,不然,指定節點 的prev的next節點爲其自身的next節點,而且令指定節點 的prev節點爲null if (prev == null) { first = next; } else { prev.next = next; x.prev = null; } //同理,若是指定節點的下一個節點爲null,表明指定節點爲尾節點,令 尾節點等於指定節點的上一個節點,不然,指定節點的next節點的prev節點 等於其自身的prev節點,且令自身的next節點等於null if (next == null) { last = prev; } else { next.prev = prev; x.next = null; } //最後,將指定節點的item也置爲null,防止內存泄漏 x.item = null; size--; modCount++; return element; } //按照索引值與對應集合類進行批量添加 public boolean addAll(int index, Collection<? extends E> c) { //檢驗index是否合法,就是檢查其是否在[0,size]範圍內,若是index爲size,就是尾節點 checkPositionIndex(index); Object[] a = c.toArray(); int numNew = a.length; //若是集合類長度爲0,那麼直接返回失敗 if (numNew == 0) return false; //若是index與size大小相等,直接設置插入位置爲尾節點 ,不然,進行遍歷查找節點,設置查找到的節點的前一個節點爲插入節點 Node<E> pred, succ; if (index == size) { succ = null; pred = last; } else { succ = node(index); pred = succ.prev; } //循環插入 for (Object o : a) { @SuppressWarnings("unchecked") E e = (E) o; Node<E> newNode = new Node<>(pred, e, null); //若是pred==null,表明index=0,此時直接插入首節點,令 首節點等於新節點,不然,直接令pred的下一個節點爲新節點,而後依序插入 if (pred == null) first = newNode; else pred.next = newNode; pred = newNode; } //若是,succ==null,表明index==size,則是直接從 尾部進行插入,因此,直接令尾節點指向插入的最後一個節點便可 ,不然,令最後一個插入節點的next等於succ, 令succ的prev等於最後一個插入節點便可(其實就是進行了一個銜接) if (succ == null) { last = pred; } else { pred.next = succ; succ.prev = pred; } //對元素數量進行增長 size += numNew; modCount++; return true; } //根據索引查找對應的節點(調用這個方法的方法已經判斷過index,因此直接使用) Node<E> node(int index) { //若是index靠近左邊,從first開始遍歷,不然,從last開始遍歷 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; } }