List集合就這么簡單【源碼剖析】

前言

聲明浅辙,本文用得是jdk1.8

前一篇已經(jīng)講了Collection的總覽:Collection總覽,介紹了一些基礎(chǔ)知識乞旦。

現(xiàn)在這篇主要講List集合的三個子類:

  • ArrayList
    • 底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組偏序。線程不安全
  • LinkedList
    • 底層數(shù)據(jù)結(jié)構(gòu)是鏈表。線程不安全
  • Vector
    • 底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組改艇。線程安全

這篇主要來看看它們比較重要的方法是如何實現(xiàn)的收班,需要注意些什么,最后比較一下哪個時候用哪個~

看這篇文章之前最好是有點數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ):Java實現(xiàn)單向鏈表谒兄,棧和隊列就是這么簡單摔桦,二叉樹就這么簡單

當(dāng)然了,如果講得有錯的地方還請大家多多包涵并不吝在評論去指正~

一承疲、ArrayList解析

image

首先邻耕,我們來講解的是ArrayList集合,它是我們用得非常非常多的一個集合~

首先燕鸽,我們來看一下ArrayList的屬性:

image

根據(jù)上面我們可以清晰的發(fā)現(xiàn):ArrayList底層其實就是一個數(shù)組兄世,ArrayList中有擴容這么一個概念,正因為它擴容啊研,所以它能夠實現(xiàn)“動態(tài)”增長

1.2構(gòu)造方法

我們來看看構(gòu)造方法來印證我們上面說得對不對:

image

1.3Add方法

add方法可以說是ArrayList比較重要的方法了御滩,我們來總覽一下:

image

1.3.1add(E e)

步驟:

  • 檢查是否需要擴容
  • 插入元素

首先,我們來看看這個方法:


    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

該方法很短党远,我們可以根據(jù)方法名就猜到他是干了什么:

  • 確認list容量削解,嘗試容量加1,看看有無必要
  • 添加元素

接下來我們來看看這個小容量(+1)是否滿足我們的需求:

image

隨后調(diào)用ensureExplicitCapacity()來確定明確的容量沟娱,我們也來看看這個方法是怎么實現(xiàn)的:

image

所以氛驮,接下來看看grow()是怎么實現(xiàn)的~

image

進去看copyOf()方法:

image

到目前為止,我們就可以知道add(E e)的基本實現(xiàn)了:

  • 首先去檢查一下數(shù)組的容量是否足夠
    • 足夠:直接添加
    • 不足夠:擴容
      • 擴容到原來的1.5倍
      • 第一次擴容后济似,如果容量還是小于minCapacity矫废,就將容量擴充為minCapacity。

1.3.2add(int index, E element)

步驟:

  • 檢查角標(biāo)
  • 空間檢查碱屁,如果有需要進行擴容
  • 插入元素

我們來看看插入的實現(xiàn):


image

我們發(fā)現(xiàn)磷脯,與擴容相關(guān)ArrayList的add方法底層其實都是arraycopy()來實現(xiàn)的

看到arraycopy(),我們可以發(fā)現(xiàn):該方法是由C/C++來編寫的娩脾,并不是由Java實現(xiàn):

image

總的來說:arraycopy()還是比較可靠高效的一個方法赵誓。

參考R大回答:https://www.zhihu.com/question/53749473

1.4 get方法

  • 檢查角標(biāo)
  • 返回元素
image

   // 檢查角標(biāo)
   private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

    // 返回元素
    E elementData(int index) {
        return (E) elementData[index];
    }

1.5 set方法

步驟:

  • 檢查角標(biāo)
  • 替代元素
  • 返回舊值
image

1.6remove方法

步驟:

  • 檢查角標(biāo)
  • 刪除元素
  • 計算出需要移動的個數(shù),并移動
  • 設(shè)置為null,讓Gc回收
image

1.7細節(jié)再說明

  • ArrayList是基于動態(tài)數(shù)組實現(xiàn)的俩功,在增刪時候幻枉,需要數(shù)組的拷貝復(fù)制
  • ArrayList的默認初始化容量是10诡蜓,每次擴容時候增加原先容量的一半熬甫,也就是變?yōu)樵瓉淼?.5倍
  • 刪除元素時不會減少容量,若希望減少容量則調(diào)用trimToSize()
  • 它不是線程安全的蔓罚。它能存放null值椿肩。
image

參考資料:

二、Vector與ArrayList區(qū)別

Vector是jdk1.2的類了豺谈,比較老舊的一個集合類郑象。

image

Vector底層也是數(shù)組,與ArrayList最大的區(qū)別就是:同步(線程安全)

Vector是同步的茬末,我們可以從方法上就可以看得出來~

image

在要求非同步的情況下厂榛,我們一般都是使用ArrayList來替代Vector的了~

如果想要ArrayList實現(xiàn)同步,可以使用Collections的方法:List list = Collections.synchronizedList(new ArrayList(...));丽惭,就可以實現(xiàn)同步了~

還有另一個區(qū)別:

  • ArrayList在底層數(shù)組不夠用時在原來的基礎(chǔ)上擴展0.5倍击奶,Vector是擴展1倍。责掏、
image
image

Vector源碼的解析可參考:

三柜砾、LinkedList解析

image

LinkedList底層是雙向鏈表~如果對于鏈表不熟悉的同學(xué)可先看看我的單向鏈表(雙向鏈表的練習(xí)我還沒做)【Java實現(xiàn)單向鏈表

理解了單向鏈表,雙向鏈表也就不難了拷橘。

image

從結(jié)構(gòu)上局义,我們還看到了LinkedList實現(xiàn)了Deque接口喜爷,因此冗疮,我們可以操作LinkedList像操作隊列和棧一樣~

image

LinkedList變量就這么幾個,因為我們操作單向鏈表的時候也發(fā)現(xiàn)了:有了頭結(jié)點檩帐,其他的數(shù)據(jù)我們都可以獲取得到了术幔。(雙向鏈表也同理)

image

3.1構(gòu)造方法

LinkedList的構(gòu)造方法有兩個:

image

3.2add方法

如果做過鏈表的練習(xí),對于下面的代碼并不陌生的~

  • add方法實際上就是往鏈表最后添加元素

    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++;
    }

3.3remove方法

image
image

實際上就是下面那個圖的操作:

image

3.4get方法

可以看到get方法實現(xiàn)就兩段代碼:

    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }

我們進去看一下具體的實現(xiàn)是怎么樣的:

dGMp3ws.png

3.5set方法

set方法和get方法其實差不多湃密,根據(jù)下標(biāo)來判斷是從頭遍歷還是從尾遍歷


    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的方法多太多了诅挑,這里我就不一一說明了。具體可參考:

四泛源、總結(jié)

其實集合的源碼看起來并不是很困難拔妥,遇到問題可以翻一翻,應(yīng)該是能夠看懂的~

ArrayList达箍、LinkedList没龙、Vector算是在面試題中比較常見的的知識點了。下面我就來做一個簡單的總結(jié):

ArrayList:

  • 底層實現(xiàn)是數(shù)組
  • ArrayList的默認初始化容量是10,每次擴容時候增加原先容量的一半硬纤,也就是變?yōu)樵瓉淼?.5倍
  • 增刪時候解滓,需要數(shù)組的拷貝復(fù)制(navite 方法由C/C++實現(xiàn))

LinkedList:

  • 底層實現(xiàn)是雙向鏈表[雙向鏈表方便實現(xiàn)往前遍歷]

Vector:

  • 底層是數(shù)組,現(xiàn)在已少用筝家,被ArrayList替代洼裤,原因有兩個:

總的來說:查詢多用ArrayList莹菱,增刪多用LinkedList缕减。

ArrayList增刪慢不是絕對的(在數(shù)量大的情況下,已測試):

  • 如果增加元素一直是使用add()(增加到末尾)的話芒珠,那是ArrayList要快
  • 一直刪除末尾的元素也是ArrayList要快【不用復(fù)制移動位置】
  • 至于如果刪除的是中間的位置的話桥狡,還是ArrayList要快

但一般來說:增刪多還是用LinkedList皱卓,因為上面的情況是極端的~

參考資料:

image

文章的目錄導(dǎo)航https://zhongfucheng.bitcron.com/post/shou-ji/gong-zhong-hao-wen-zhang-zheng-li

如果文章有錯的地方歡迎指正裹芝,大家互相交流。習(xí)慣在微信看技術(shù)文章娜汁,想要獲取更多的Java資源的同學(xué)嫂易,可以關(guān)注微信公眾號:Java3y。為了大家方便掐禁,剛新建了一下qq群:742919422怜械,大家也可以去交流交流。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末傅事,一起剝皮案震驚了整個濱河市缕允,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蹭越,老刑警劉巖障本,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異响鹃,居然都是意外死亡驾霜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門买置,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粪糙,“玉大人,你說我怎么就攤上這事忿项∪馗裕” “怎么了脆栋?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長洒擦。 經(jīng)常有香客問我椿争,道長,這世上最難降的妖魔是什么熟嫩? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任秦踪,我火速辦了婚禮,結(jié)果婚禮上掸茅,老公的妹妹穿的比我還像新娘椅邓。我一直安慰自己,他們只是感情好昧狮,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布景馁。 她就那樣靜靜地躺著,像睡著了一般逗鸣。 火紅的嫁衣襯著肌膚如雪合住。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天撒璧,我揣著相機與錄音透葛,去河邊找鬼。 笑死卿樱,一個胖子當(dāng)著我的面吹牛僚害,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播繁调,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼萨蚕,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蹄胰?” 一聲冷哼從身側(cè)響起岳遥,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎烤送,沒想到半個月后寒随,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡帮坚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了互艾。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片试和。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖纫普,靈堂內(nèi)的尸體忽然破棺而出阅悍,到底是詐尸還是另有隱情好渠,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布节视,位于F島的核電站拳锚,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏寻行。R本人自食惡果不足惜霍掺,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望拌蜘。 院中可真熱鬧杆烁,春花似錦、人聲如沸简卧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽举娩。三九已至析校,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間铜涉,已是汗流浹背勺良。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留骄噪,地道東北人尚困。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像链蕊,于是被迫代替她去往敵國和親事甜。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容