學習狀況記錄java
記錄在學習Java容器 知識點中,關於List
的須要重點記錄的知識點。git
知識點概覽:github
底層數據結構:面試
10
。**c#
size
、first
、last
。size
是雙向鏈表中節點的個數,first
和last
分別指向第一個和最後一個節點的引用。插入和刪除是否受元素位置的影響:數組
add(E e)
方法的時候, ArrayList 會默認在將指定的元素追加到此列表的末尾,這種狀況時間複雜度就是O(1)。可是若是要在指定位置 i 插入和刪除元素的話(add(int index, E element)
)時間複雜度就爲 O(n-i)。由於在進行上述操做的時候集合中第 i 和第 i 個元素以後的(n-i)個元素都要執行向後位/向前移一位的操做。實際就是近似O(n)。get(int index)
方法)。前面的圖中咱們能夠看到ArrayList 繼承了三個接口,後面兩個都是比較熟悉的,分別是標識對象可複製和可序列化。安全
那麼RandomAccess
接口表明什麼呢?數據結構
前面的關於ArrayList 與 LinkedList 的對比當中,有一點就是,app
是否支持快速隨機訪問:這個也是由底層實現決定的,LinkedList 不支持高效的隨機元素訪問,而 ArrayList 支持。
快速隨機訪問就是經過元素的序號快速獲取元素對象(對應於
get(int index)
方法)。
而RandomAccess
接口 就是用來 標識該類支持快速隨機訪問。 查看源碼能夠發現,這個接口內部沒有任何的定義。僅僅是起標識做用。dom
好比在Collections.binarySearch()
方法中,
實現了RandomAccess接口的List使用索引遍歷,而未實現RandomAccess接口的List使用迭代器遍歷。
總結一句話:實現RandomAccess接口的List能夠經過for循環來遍歷數據比使用iterator遍歷數據更高效,未實現RandomAccess接口的List能夠經過iterator遍歷數據比使用for循環來遍歷數據更高效。固然對於ArrayList來講,for循環遍歷和Iterator方式遍歷差距不大,可是對於LinkedList這種沒有實現的來講,兩種遍歷方式效率差距就有點大了。這主要是由於底層實現不一樣。
與 ArrayList 相對應的,LinkedList 中也有一個值得好好研究的接口,那就是Deque
接口。
Deque - double-ended queue
,中文名爲雙端隊列。
咱們都知道 Queue
是一個隊列,遵循 FIFO 準則,咱們也知道 Stack
是一個棧結構,遵循 FILO 準則。 而Deque
這個雙端隊列就厲害了,它既能夠實現棧的操做,也能夠實現隊列的操做,換句話說,實現了這個接口的類,既能夠做爲棧使用也能夠做爲隊列使用。
如何做爲隊列使用呢? Deque
實現了 Queue
,因此 Queue
全部的方法 Deque
都有,下面比較的是Deque
區別 Queue
的方法:
Queue | Deque |
---|---|
add(e) | addLast() |
offer(e) | offerLast() |
remove() | removeFirst() |
poll() | pollFirst() |
element() | getFirst() |
peek() | peekFirst() |
如何做爲棧使用呢? 下面咱們來看看下雙端隊列做爲棧 Stack
使用的時候方法對應關係。
Stack | Deque |
---|---|
push(e) | addFirst(e) |
pop() | removeFirst() |
peek() | peekFirst() |
由於篇幅有限,具體實現源碼就不帶你們去分析了。
引一篇好文:搞懂 Java LinkedList 源碼
這是一個很頻繁的面試點,故記錄一下。
如下是源碼部分。
add()
方法開始入手ensureCapacityInternal(size + 1)
確認當前數組能否容納 size + 1
個元素,若是不夠進行擴容grow(minCapacity)
這就是具體擴容的邏輯
oldCapacity + (oldCapacity >> 1)
,也就是舊容量的1.5
倍Arrays.copyOf()
這個方法,把原數組整個複製到新數組中,這個操做代價很高,因此 不少地方包括阿里開發手冊上也會建議 在集合初始化的時候就指定好大概的容量大小,減小擴容的次數。ArrayList 與 Vector 的底層實現都是 Object 數組,因此二者使用和特性上很是相似。
不一樣的是,
若是是想要達到線程安全的目的,Vector 有其餘的替代方案:
Collections.synchronizedList()
獲得一個線程安全的ArrayList(這類的Collections.synchronized*() 就是一層Wrapper,看源碼就知道了)