muduo原始碼解析21-Socket類
1.基本原理
底層是一個雙向連結串列來維護資料,在JDK1.7之前是一個雙向迴圈連結串列
2.優缺點
1.優點
插入刪除效能好,容量沒有限制
可以用作記憶體佇列或棧
2.缺點
隨機訪問效能差
3.原始碼分析
1.add()方法
public boolean add(E e) {
linkLast(e);
return true;
}
呼叫了linkLast方法,然後返回true
linkLast方法如下:
首先讓l指向last的位置,然後建立一個Node物件newNode,prev指標指向last,next指標指向null,元素為e,然後將last指向newNode節點,進入if判斷,如果l為null說明是第一個元素,讓first指向newNode,否則的話將newCode連結到l後面,最後進行size++
transient Node<E> first; transient Node<E> last; 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; } } 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++; }
小結:
1.使用臨時指標l記錄最後一個元素的位子
2.建立一個新的節點,讓節點的prev指標指向l
3.再將last指標指向新的元素,如果是第一次新增,也會將first指標指向該節點
2.add(int index,E element)方法
該方法是在某個位置增加一個元素,首先判斷index是否在0-size的範圍,如果不在報出異常,然後根據index判斷,如果index==size,呼叫linkLast方法向尾節點插入元素,否則呼叫linkBefore方法插入
public void add(int index, E element) { checkPositionIndex(index); if (index == size) linkLast(element); else linkBefore(element, node(index)); }
首先通過node(int index)定位元素:
這裡將size處以2來和index比較,如果index在左半邊,從前開始尋找元素如果index在右半邊,從後尋找元素(二分),確認了以後,執行linkBefore方法
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;
}
}
linkBefore方法如下:
首先將之前node定位到的元素作為succ傳入,pred指向它前一個節點,然後類似於linkLast方法插入元素
void linkBefore(E e, Node<E> succ) {
// assert succ != null;
final Node<E> pred = succ.prev;
final Node<E> newNode = new Node<>(pred, e, succ);
succ.prev = newNode;
if (pred == null)
first = newNode;
else
pred.next = newNode;
size++;
modCount++;
}
3.removeLast方法
public E removeLast() {
final Node<E> l = last;
if (l == null)
throw new NoSuchElementException();
return unlinkLast(l);
}
使用l記錄尾節點的位置,然後呼叫unlinkLast方法:
首先通過l.prev找到前一個元素,記為prev,然後將l斷開,將last指標指向prev節點,最後返回最後一個元素
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;
}
4.removeFirst方法
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
使用f記錄頭節點的位置,然後呼叫unlinkFirst方法:
之後類似於上面的方法
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;
}
5.remove(int index)方法
public E remove(int index) {
checkElementIndex(index);
return unlink(node(index));
}
首先通過node方法定位節點,然後呼叫unlink方法:
通過next和prev兩個指標斷開x的前後指標,將next和prev重新相接,就可以從某個位置刪除節點
E unlink(Node<E> x) {
// assert x != null;
final E element = x.item;
final Node<E> next = x.next;
final Node<E> prev = x.prev;
if (prev == null) {
first = next;
} else {
prev.next = next;
x.prev = null;
}
if (next == null) {
last = prev;
} else {
next.prev = prev;
x.next = null;
}
x.item = null;
size--;
modCount++;
return element;
}