LinkedList 源碼分析
LinkedList 源碼分析
1.結構
1. 繼承
??該類繼承自 AbstractSequentialList 這個是由於他是一個順序的列表,所以說繼承的是一個順序的 List
2. 實現
這個類實現的接口比較多,具體如下:
- 首先這個類是一個 List 自然有 List 接口
- 然後由於這個類是實現了 Deque 這個接口是雙端隊列的接口,所以說它是具有雙端隊列的特性的。後面我們會看到很多關於雙端隊列的方法。
- 然後就是兩個集合框架肯定會實現的兩個接口 Cloneable, Serializable 。
3. 主要字段
1. 屬性字段
transient int size = 0;
//指向鏈表的頭指針和尾指針
transient Node<E> first;
transient Node<E> last;
2. Node 節點
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;
}
}
4. 主要方法概覽
- ctor-2
- addFirst
- addLast
- addAll
- add
- indexOf
- lastIndexOf
- peek 獲取第一個元素,是 null 就返回 null
- peekFirst/Last 獲取第一個最後一個元素
- poll 刪除第一個元素並返回 沒有返回 null
- pollFirst/Last
- offer 調用了 add
- offerFirst/Last
- push
- pop
- set
- remove(noArgs) == removeFirst 繼承自 deque
- remove(E e) 查找刪除
- read/writeObject 還是手動的序列化,原因一樣,直接序列化元素而沒有 pre/next
2. 構造方法分析
只有兩個構造方法。其中一個是默認的空構造也就是生成一個空的 LinkedList 另外一個就是接受一個 Collection 接口。裏面調用了 PutAll 方法。
public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
this();
addAll(c);
}
3. 主要方法分析
1. add
這個方法就直接調用了 linkLast
而 linkLast
裏面就是直接把元素添加到元素的結尾。
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
2. addFrist/Last
這兩個方法同上還是調用了 linkFirst
和 linkLast
所以說這幾個添加修改的方法基本都是靠底層的同樣的方法實現的。
public void addFirst(E e) {
linkFirst(e);
}
public void addLast(E e) {
linkLast(e);
}
3. addAll
該方法我們在構造方法中也看到了,在它裏面實現的時候和 ArrayList 一樣是直接把集合轉成數組,然後進行創建新的節點插入進來。
```java
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);
Object[] a = c.toArray();
int numNew = a.length;
if (numNew == 0)
return false;
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);
if (pred == null)
first = newNode;
else
pred.next = newNode;
pred = newNode;
}
if (succ == null) {
last = pred;
} else {
pred.next = succ;
succ.prev = pred;
}
size += numNew;
modCount++;
return true;
}
```
4. indexOf
這個方法裏面采用 for 循環遍歷,遍歷的時候是從頭結點開始遍歷,只要找到那個元素立即返回,而不繼續進行下去。
public int indexOf(Object o) {
int index = 0;
if (o == null) {
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;
}
5. lastIndexOf
這個方法和上面的方法實現的方式一樣的,但是註意這個方法的意思是找到最後一個與之匹配的元素,他並不是從頭開始找,而是直接從尾節點開始遍歷。做法同理找到即停止。
6. peek/peekFirst/peekLast
peek
方法的意思就是返回最頂端的元素,如果這個元素不存在,那麽直接返回 null
。之後還有 peekFirst
這類的就是返回第一個的意思。底層調用的就是頭結點的屬性。這些方法其實在 Collection 接口中是不存在的,主要就是因為他實現了 Deque 所帶來的的新特性。
7. poll/pollFirst/pollLast
poll
用來刪除頭結點並返回,如果不存在就返回 null
剩下的兩個方法同理。
8. offer/offerFirst/offerLast
插入頭結點。
9. push/pop
底層的方法就是 addFirst 和 removeFirst
10. remove(noargs)/remove(E e)
無參的調用 removeFirst 有參數的就是去查找然後刪除。
11. read/writeObject
這裏同 ArrayList
自己手動的進行了序列化。序列化的時候只是對 Node 節點裏面的元素進行序列化,而前驅後繼直接省略,也是節約空間的想法。
4.總結
好,其實在完全理解 ArrayList
的基礎之上看這篇文章就比較好理解,裏面的操作更加簡單。只是註意一下兩者的區別,實現了 Deque
帶來的不少新的方法。
LinkedList 源碼分析