聲明,本文用得是jdk1.8
前一篇已經講了Collection的總覽:Collection總覽,介紹了一些基礎知識。java
如今這篇主要講List集合的三個子類:node
ArrayList面試
LinkedListc#
Vector數組
這篇主要來看看它們比較重要的方法是如何實現的,須要注意些什麼,最後比較一下哪一個時候用哪一個~安全
看這篇文章以前最好是有點數據結構的基礎:Java實現單向鏈表,棧和隊列就是這麼簡單,二叉樹就這麼簡單微信
固然了,若是講得有錯的地方還請你們多多包涵並不吝在評論去指正~數據結構
首先,咱們來說解的是ArrayList集合,它是咱們用得很是很是多的一個集合~post
首先,咱們來看一下ArrayList的屬性:性能
根據上面咱們能夠清晰的發現:ArrayList底層其實就是一個數組,ArrayList中有擴容這麼一個概念,正由於它擴容,因此它可以實現「動態」增加
咱們來看看構造方法來印證咱們上面說得對不對:
add方法能夠說是ArrayList比較重要的方法了,咱們來總覽一下:
步驟:
首先,咱們來看看這個方法:
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
該方法很短,咱們能夠根據方法名就猜到他是幹了什麼:
接下來咱們來看看這個小容量(+1)是否知足咱們的需求:
隨後調用ensureExplicitCapacity()
來肯定明確的容量,咱們也來看看這個方法是怎麼實現的:
因此,接下來看看grow()
是怎麼實現的~
進去看copyOf()
方法:
到目前爲止,咱們就能夠知道add(E e)
的基本實現了:
首先去檢查一下數組的容量是否足夠
不足夠:擴容
步驟:
咱們來看看插入的實現:
咱們發現,與擴容相關ArrayList的add方法底層其實都是arraycopy()
來實現的
看到arraycopy()
,咱們能夠發現:該方法是由C/C++來編寫的,並非由Java實現:
總的來講:arraycopy()
仍是比較可靠高效的一個方法。
參考R大回答:https://www.zhihu.com/question/53749473
// 檢查角標 private void rangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } // 返回元素 E elementData(int index) { return (E) elementData[index]; }
步驟:
步驟:
參考資料:
Vector是jdk1.2的類了,比較老舊的一個集合類。
Vector底層也是數組,與ArrayList最大的區別就是:同步(線程安全)
Vector是同步的,咱們能夠從方法上就能夠看得出來~
在要求非同步的狀況下,咱們通常都是使用ArrayList來替代Vector的了~
若是想要ArrayList實現同步,可使用Collections的方法:List list = Collections.synchronizedList(new ArrayList(...));
,就能夠實現同步了~
還有另外一個區別:
Vector源碼的解析可參考:
LinkedList底層是雙向鏈表~若是對於鏈表不熟悉的同窗可先看看個人單向鏈表(雙向鏈表的練習我還沒作)【Java實現單向鏈表】
理解了單向鏈表,雙向鏈表也就不難了。
從結構上,咱們還看到了LinkedList實現了Deque接口,所以,咱們能夠操做LinkedList像操做隊列和棧同樣~
LinkedList變量就這麼幾個,由於咱們操做單向鏈表的時候也發現了:有了頭結點,其餘的數據咱們均可以獲取獲得了。(雙向鏈表也同理)
LinkedList的構造方法有兩個:
若是作過鏈表的練習,對於下面的代碼並不陌生的~
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++; }
實際上就是下面那個圖的操做:
能夠看到get方法實現就兩段代碼:
public E get(int index) { checkElementIndex(index); return node(index).item; }
咱們進去看一下具體的實現是怎麼樣的:
set方法和get方法其實差很少,根據下標來判斷是從頭遍歷仍是從尾遍歷
public E set(int index, E element) { checkElementIndex(index); Node<E> x = node(index); E oldVal = x.item; x.item = element; return oldVal; }
......LinkedList的方法比ArrayList的方法多太多了,這裏我就不一一說明了。具體可參考:
其實集合的源碼看起來並非很困難,遇到問題能夠翻一翻,應該是可以看懂的~
ArrayList、LinkedList、Vector算是在面試題中比較常見的的知識點了。下面我就來作一個簡單的總結:
ArrayList:
LinkedList:
Vector:
底層是數組,如今已少用,被ArrayList替代,緣由有兩個:
總的來講:查詢多用ArrayList,增刪多用LinkedList。
ArrayList增刪慢不是絕對的(在數量大的狀況下,已測試):
add()
(增長到末尾)的話,那是ArrayList要快但通常來講:增刪多仍是用LinkedList,由於上面的狀況是極端的~
參考資料:
文章的目錄導航:https://zhongfucheng.bitcron.com/post/shou-ji/gong-zhong-hao-wen-zhang-zheng-li
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠 關注微信公衆號:Java3y。爲了你們方便,剛新建了一下 qq羣:742919422,你們也能夠去交流交流。