ArrayList和LinkedList源碼對比總結(jié)

關(guān)于ArrayList的源碼德迹,給出幾點比較重要的總結(jié):

ArrayList是基于數(shù)組實現(xiàn)的闹蒜,是一個動態(tài)數(shù)組寺枉,其容量能自動增長,類似于C語言中的動態(tài)申請內(nèi)存绷落,動態(tài)增長內(nèi)存姥闪。

ArrayList不是線程安全的,只能在單線程環(huán)境下砌烁,多線程環(huán)境下可以考慮用collections.synchronizedList(List l)函數(shù)返回一個線程安全的ArrayList類筐喳,也可以使用concurrent并發(fā)包下的CopyOnWriteArrayList類催式。

ArrayList實現(xiàn)了Serializable接口,因此它支持序列化避归,能夠通過序列化傳輸荣月,實現(xiàn)了RandomAccess接口,支持快速隨機訪問梳毙,實際上就是通過下標序號進行快速訪問,實現(xiàn)了Cloneable接口账锹,能被克隆。

  1. 注意其三個不同的構(gòu)造方法奸柬。無參構(gòu)造方法構(gòu)造的ArrayList的容量默認為10,帶有Collection參數(shù)的構(gòu)造方法廓奕,將Collection轉(zhuǎn)化為數(shù)組賦給ArrayList的實現(xiàn)數(shù)組elementData。
  2. 注意擴充容量的方法ensureCapacity懂从。ArrayList在每次增加元素(可能是1個授段,也可能是一組)時侵贵,都要調(diào)用該方法來確保足夠的容量。當容量不足以容納當前的元素個數(shù)時窍育,就設(shè)置新的容量為舊的容量的1.5倍加1,如果設(shè)置后的新容量還不夠宴胧,則直接新容量設(shè)置為傳入的參數(shù)(也就是所需的容量),而后用Arrays.copyof()方法將元素拷貝到新的數(shù)組(詳見下面的第3點)恕齐。從中可以看出,當容量不夠時显歧,每次增加元素仪或,都要將原來的元素拷貝到一個新的數(shù)組中,非常之耗時士骤,也因此建議在事先能確定元素數(shù)量的情況下范删,才使用ArrayList,否則建議使用LinkedList拷肌。
  3. ArrayList的實現(xiàn)中大量地調(diào)用了Arrays.copyof()和System.arraycopy()方法到旦。我們有必要對這兩個方法的實現(xiàn)做下深入的了解旨巷。
    首先來看Arrays.copyof()方法。它有很多個重載的方法添忘,但實現(xiàn)思路都是一樣的采呐,我們來看泛型版本的源碼:
public static <T> T[] copyOf(T[] original, int newLength) {  
    return (T[]) copyOf(original, newLength, original.getClass());  
} 

很明顯調(diào)用了另一個copyof方法,該方法有三個參數(shù)昔汉,最后一個參數(shù)指明要轉(zhuǎn)換的數(shù)據(jù)的類型,其源碼如下:

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {  
    T[] copy = ((Object)newType == (Object)Object[].class)  
        ? (T[]) new Object[newLength]  
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);  
    System.arraycopy(original, 0, copy, 0,  
                     Math.min(original.length, newLength));  
    return copy;  
}

這里可以很明顯地看出拴清,該方法實際上是在其內(nèi)部又創(chuàng)建了一個長度為newlength的數(shù)組靶病,調(diào)用System.arraycopy()方法,將原來數(shù)組中的元素復(fù)制到了新的數(shù)組中口予。

下面來看System.arraycopy()方法娄周。該方法被標記了native,調(diào)用了系統(tǒng)的C/C++代碼沪停,在JDK中是看不到的煤辨,但在openJDK中可以看到其源碼。該函數(shù)實際上最終調(diào)用了C語言的memmove()函數(shù)木张,因此它可以保證同一個數(shù)組內(nèi)元素的正確復(fù)制和移動众辨,比一般的復(fù)制方法的實現(xiàn)效率要高很多,很適合用來批量處理數(shù)組舷礼。Java強烈推薦在復(fù)制大量數(shù)組元素時用該方法鹃彻,以取得更高的效率。

  1. 注意ArrayList的兩個轉(zhuǎn)化為靜態(tài)數(shù)組的toArray方法妻献。

第一個蛛株,Object[] toArray()方法。該方法有可能會拋出java.lang.ClassCastException異常育拨,如果直接用向下轉(zhuǎn)型的方法谨履,將整個ArrayList集合轉(zhuǎn)變?yōu)橹付愋偷腁rray數(shù)組,便會拋出該異常熬丧,而如果轉(zhuǎn)化為Array數(shù)組時不向下轉(zhuǎn)型笋粟,而是將每個元素向下轉(zhuǎn)型,則不會拋出該異常析蝴,顯然對數(shù)組中的元素一個個進行向下轉(zhuǎn)型矗钟,效率不高,且不太方便嫌变。

第二個吨艇, T[] toArray(T[] a)方法东涡。該方法可以直接將ArrayList轉(zhuǎn)換得到的Array進行整體向下轉(zhuǎn)型(轉(zhuǎn)型其實是在該方法的源碼中實現(xiàn)的)组贺,且從該方法的源碼中可以看出失尖,參數(shù)a的大小不足時掀潮,內(nèi)部會調(diào)用Arrays.copyOf方法仪吧,該方法內(nèi)部創(chuàng)建一個新的數(shù)組返回鞠眉,因此對該方法的常用形式如下:

public static Integer[] vectorToArray2(ArrayList<Integer> v) {
Integer[] newText = (Integer[])v.toArray(new Integer[0]);
return newText;
}

  1. ArrayList基于數(shù)組實現(xiàn)械蹋,可以通過下標索引直接查找到指定位置的元素哗戈,因此查找效率高,但每次插入或刪除元素暇仲,就要大量地移動元素奈附,插入刪除元素的效率低斥滤。

  2. 在查找給定元素索引值等的方法中勉盅,源碼都將該元素的值分為null和不為null兩種情況處理草娜,ArrayList中允許元素為null。

關(guān)于LinkedList的源碼茬贵,給出幾點比較重要的總結(jié):

LinkedList簡介 LinkedList是基于雙向循環(huán)鏈表(從源碼中可以很容易看出)實現(xiàn)的,除了可以當作鏈表來操作外老充,它還可以當作棧啡浊,隊列和雙端隊列來使用胶背。

LinkedList同樣是非線程安全的奄妨,只在單線程下適合使用砸抛。

LinkedList實現(xiàn)了Serializable接口树枫,因此它支持序列化,能夠通過序列化傳輸奔誓,實現(xiàn)了Cloneable接口厨喂,能被克隆庄呈。

  1. 從源碼中很明顯可以看出,LinkedList的實現(xiàn)是基于雙向循環(huán)鏈表的斜纪,且頭結(jié)點中不存放數(shù)據(jù)盒刚。
  1. 注意兩個不同的構(gòu)造方法绿贞。無參構(gòu)造方法直接建立一個僅包含head節(jié)點的空鏈表,包含Collection的構(gòu)造方法贮聂,先調(diào)用無參構(gòu)造方法建立一個空鏈表吓懈,然后將Collection中的數(shù)據(jù)加入到鏈表的尾部后面耻警。

  2. 在查找和刪除某元素時,源碼中都劃分為該元素為null和不為null兩種情況來處理腮恩,LinkedList中允許元素為null温兼。

  3. LinkedList是基于鏈表實現(xiàn)的募判,因此不存在容量不足的問題,所以這里沒有擴容的方法释液。

  4. 注意源碼中的Entry entry(int index)方法误债。該方法返回雙向鏈表中指定位置處的節(jié)點寝蹈,而鏈表中是沒有下標索引的登淘,要指定位置出的元素,就要遍歷該鏈表槽惫,從源碼的實現(xiàn)中界斜,我們看到這里有一個加速動作合冀。源碼中先將index與長度size的一半比較,如果index<size/2开缎,就只從位置0往后遍歷到位置index處奕删,而如果index>size/2疗认,就只從位置size往前遍歷到位置index處横漏。這樣可以減少一部分不必要的遍歷缎浇,從而提高一定的效率(實際上效率還是很低)。

  5. 注意鏈表類對應(yīng)的數(shù)據(jù)結(jié)構(gòu)Entry二蓝。如下;

// 雙向鏈表的節(jié)點所對應(yīng)的數(shù)據(jù)結(jié)構(gòu)侣夷。    
// 包含3部分:上一節(jié)點仑乌,下一節(jié)點琴锭,當前節(jié)點值决帖。    
private static class Entry<E> {    
    // 當前節(jié)點所包含的值    
    E element;    
    // 下一個節(jié)點    
    Entry<E> next;    
    // 上一個節(jié)點    
    Entry<E> previous;    
  
    /**   
     * 鏈表節(jié)點的構(gòu)造函數(shù)。   
     * 參數(shù)說明:   
     *   element  —— 節(jié)點所包含的數(shù)據(jù)   
     *   next      —— 下一個節(jié)點   
     *   previous —— 上一個節(jié)點   
     */   
    Entry(E element, Entry<E> next, Entry<E> previous) {    
        this.element = element;    
        this.next = next;    
        this.previous = previous;    
    }    
}   

  1. LinkedList是基于鏈表實現(xiàn)的,因此插入刪除效率高刻像,查找效率低(雖然有一個加速動作)细睡。

  2. 要注意源碼中還實現(xiàn)了棧和隊列的操作方法,因此也可以作為棧湃缎、隊列和雙端隊列來使用嗓违。

ArrayList和LinkedList在性能上各有優(yōu)缺點,都有各自所適用的地方比庄,總的說來可以描述如下:

1.對ArrayList和LinkedList而言佳窑,在列表末尾增加一個元素所花的開銷都是固定的神凑。對ArrayList而言溉委,主要是在內(nèi)部數(shù)組中增加一項瓣喊,指向所添加的元素藻三,偶爾可能會導致對數(shù)組重新進行分配棵帽;而對LinkedList而言逗概,這個開銷是統(tǒng)一的忘衍,分配一個內(nèi)部Entry對象枚钓。

2.在ArrayList的中間插入或刪除一個元素意味著這個列表中剩余的元素都會被移動;而在LinkedList的中間插入或刪除一個元素的開銷是固定的秘噪。

3.LinkedList不支持高效的隨機元素訪問狸吞。

4.ArrayList的空間浪費主要體現(xiàn)在在list列表的結(jié)尾預(yù)留一定的容量空間,而LinkedList的空間花費則體現(xiàn)在它的每一個元素都需要消耗相當?shù)目臻g

可以這樣說:當操作是在一列數(shù)據(jù)的后面添加數(shù)據(jù)而不是在前面或中間,并且需要隨機地訪問其中的元素時,使用ArrayList會提供比較好的性能;當你的操作是在一列數(shù)據(jù)的前面或中間添加或刪除數(shù)據(jù),并且按照順序訪問其中的元素時,就應(yīng)該使用LinkedList了蹋偏。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末便斥,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子威始,更是在濱河造成了極大的恐慌枢纠,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件黎棠,死亡現(xiàn)場離奇詭異晋渺,居然都是意外死亡,警方通過查閱死者的電腦和手機脓斩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來恋捆,“玉大人昭卓,你說我怎么就攤上這事绰垂〔颍” “怎么了南蹂?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵该默,是天一觀的道長匣摘。 經(jīng)常有香客問我囊咏,道長葛家,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任桌吃,我火速辦了婚禮逗物,結(jié)果婚禮上摆寄,老公的妹妹穿的比我還像新娘田盈。我一直安慰自己蛮拔,他們只是感情好肛跌,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布赠法。 她就那樣靜靜地躺著侧纯,像睡著了一般眶熬。 火紅的嫁衣襯著肌膚如雪脊凰。 梳的紋絲不亂的頭發(fā)上最岗,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天蝴乔,我揣著相機與錄音练湿,去河邊找鬼宁脊。 笑死碧信,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的呈枉。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼羡藐,長吁一口氣:“原來是場噩夢啊……” “哼岸晦!你這毒婦竟也來了倒慧?” 一聲冷哼從身側(cè)響起溅固,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤苛秕,失蹤者是張志新(化名)和其女友劉穎艇劫,沒想到半個月后吼驶,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡店煞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年蟹演,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片顷蟀。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡酒请,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鸣个,到底是詐尸還是另有隱情羞反,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布囤萤,位于F島的核電站昼窗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏涛舍。R本人自食惡果不足惜澄惊,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望富雅。 院中可真熱鬧掸驱,春花似錦、人聲如沸没佑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽图筹。三九已至帅刀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間远剩,已是汗流浹背扣溺。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留瓜晤,地道東北人锥余。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像痢掠,于是被迫代替她去往敵國和親驱犹。 傳聞我的和親對象是個殘疾皇子嘲恍,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

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