一起看源碼:深入List分支LinkedList,順便說一下Vector


簡介: LinkedList 是通過雙向鏈表去實現的,他的數據結構具有雙向鏈表結構的優缺點,既然是雙向鏈表,那麼它的順序訪問會非常高效,而隨機訪問效率比較低(沒有下標)。

繼承結構

在這裏插入圖片描述
Queue:隊列接口,一端進另一端出。
Deque:雙端隊列接口,兩端都能進,兩端都能出。從而給LinkedList提供getFirst()和getLast(),addFirst(E e)和addLast(E e)方法
AbstractSequentialList:繼承AbstractList,主要就是實現了get,set,add,remove,iterator等方法

LinkedList

LinkedList它包含一個非常重要的私有的靜態內部類:Node(節點)。
說明:Node 是雙向鏈表節點所對應的數據結構,它包括的屬性有:
item:當前節點所包含的值
prev:上一個節點
next:下一個節點
在這裏插入圖片描述
除此之外LinkedList類中還有幾個重要的屬性:
int size:元素的個數
Node first:第一個元素節點
Node last:最後一個元素節點

由於 LinkedList 實現了 List 的接口,所有必然具備 List 的特性

LinkedList 的下標搜索get(int index)

我們都知道LinkedList是沒有索引得啊,那麼List接口中定義的一個方法 get (int index)在LinkedList 到底是如何實現得呢?
接下來我們一起看源碼,一步步的探究一下:

假設我們傳入索引爲1,集合的大小爲10吧。

1.找到LinkedList 類中的get(int index)方法
checkElementIndex(index):調這個方法就是對下標是否越界的檢查,越界了就拋IndexOutOfBoundsException我們都知道。
這裏傳入的索引爲1,肯定不越界的。直接進入下一步

在這裏插入圖片描述
2.進入node(int index)方法,傳入1
在這裏插入圖片描述
自上往下解析:
if判斷條件:index < (size >> 1)index爲1,size爲10。1<10/2肯定爲true嘛。
進入if語句:拿到第一個元素的節點爲x,然後進行了正序遍歷(看else語句中是不是倒序遍歷啊,他倆是相反的)
遍歷:我們現在的index爲1對吧。第一次遍歷i=0;滿足i<index,進行遍歷操作。拿到第一個元素的下一個節點重新賦值給x,第二次遍歷i=1;index=1是不是不滿足i<index了,那麼return x,就拿到我們需要的節點了。
3.返回到get方法中
node(index).item; 是不是就拿到該節點的元素值了。

總結:這就是LinkedList的get(int index)的操作。並不是通過索引來直接獲取的,因爲雙向鏈表是沒有元素索引的。所以爲了提高效率,設計者採用了二分法來操作(如果要找的元素位置比size的一半要小,那麼就從頭開始遍歷。反之就從尾開始倒序遍歷)
set(int index, E element)的操作也是這樣操作的
通過上面的總結,我們發現確實針對下標位(索引)的隨機訪問,數組的優勢很明顯

LinkedList 內部的其他操作

在 LinkedList 中具體實現,由於他的數據結構的原因,我們從頭尾獲取元素還是非常簡單的。都知道first和last保存着第一個元素和最後一個元素。那麼這兩個變量是怎麼被賦值的呢?不用想肯定在添加元素或者刪除元素是都要重新給他賦值的。

這裏就以add(E e)方法爲例:假設是第一次添加元素

1.找到add方法
在這裏插入圖片描述
2,進入linkLast() 方法傳入所添加的元素

在這裏插入圖片描述
自上往下解析:
Node l = last:將last賦值給l變量:此一次添加元素時,last還沒賦值肯定爲null即l也爲null。
new Node<>(l, e, null):new了一個新的節點對象,l:上一個節點、e:添加的元素值、新增的元素肯定沒有下一個節點吧,所以爲null
last = newNode:將當前節點賦值給last最後一個節點。
if (l == null){ first = newNode;}:條件滿足吧,所以當前節點也賦值給first第一個節點
size++;modCount++;這就不用說了吧(溫馨提示:在ArrayList的文章中說的很詳細)

注意:第一次添加元素,那麼這個節點肯定是第一個也是最後一個,對吧

其他操作對照源碼進行品讀,其實看源碼並沒有想象的難,挑能看懂的看就行啦哈哈

淺析併發安全的卻過時的 Vector

簡介:Vector 的底層與我們的 ArrayList 類似.都是以動態數組的方式進行對象的存儲

說到Vector,都知道是線程同步操作安全的,爲什麼呢?它底層的源碼是怎樣的?下面就來看一看:

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
看了源碼是不是感覺:臥槽只是加了synchronized關鍵字啊。其實Vector它就是這樣子的。很多對外的方法都是用 Synchronized 關鍵字進行修飾的. 所以通過 vector 進行操作性能並不高.所以慢慢被放棄了。

List 接口實現類的併發安全保證

要保證 List 接口實現的集合對象在同步操作時能夠線程安全.我們可以使用下面的方式:
List list = Collections.synchronizedList(new ArrayList());
最終都是返回 SynchronizedList 對象
在這裏插入圖片描述
SynchronizedList 中指定了Object mutex爲鎖對象,後續的操作中都用mutex對象來鎖。
在這裏插入圖片描述
簡單說一下Vector和SynchronizedList的區別:
1.擴容機制不同Vector擴容爲原來的2倍長度,SynchronizedList和ArrayList一樣擴容爲原來1.5倍
2.SynchronizedList有很好的擴展和兼容功能。他可以將所有的List的子類轉成線程安全的類。
3.使用SynchronizedList的時候,進行遍歷時要手動進行同步處理 。
4.SynchronizedList可以指定鎖定的對象。

發佈了21 篇原創文章 · 獲贊 34 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章