1.底層實現(xiàn)層面:
ArrayList底層是由數(shù)組實現(xiàn),是一個動態(tài)數(shù)組,而LinkedList底層是一個雙向鏈表。其實光憑這一點就可以回答很多不同點。
ArrayList由于底層是數(shù)組所以當需要往里面添加一個元素時(動態(tài)數(shù)組假設長度足夠),只需要往指定的數(shù)組中插入即可,無需在堆中尋找其它的內(nèi)存空間。但是它不足的地方是,當需要在ArrayList中add元素時,需要把索引在它后面的元素向后移動,而且當空間不足的時候還需要動態(tài)擴容(重新創(chuàng)建一個新數(shù)組,新數(shù)組是舊數(shù)組的1.5倍,如果空間還不足就直接設設為所需的大?。?。而LinkedList底層是一個雙向循環(huán)列表,他在插入時雖然需要為每一個對象分配內(nèi)存,但是不存在擴容問題。
這樣一來,當往這兩個容器內(nèi)隨機插入適當數(shù)量的元素時,LinkedList所需的時間比ArrayList少,但是當往兩個容器中順序插入大量元素時,由于LinkedList每次都需要為其元素分配內(nèi)存所以不會有ArrayList塊。對ArrayList和LinkedList而言,在列表末尾增加一個元素所花的開銷都是固定的。
再來說說消耗,LinkedList的消耗主要體現(xiàn)在它的每一個元素都要相當?shù)目臻g,而ArrayList空間消耗體現(xiàn)在尾部預留一定的空間。
2.源碼層面
ArrayList中的add(index,value),remove(index),remove(value)都需要重建一個數(shù)組再把原來的復制到新創(chuàng)建的數(shù)組中去。原來的數(shù)組需要垃圾回收器去處理,這種數(shù)組內(nèi)存大,又是朝生夕死的對gc來說簡直就是災難。(一不小心還晉升到了老年代)
ArrayList不是線程安全的,只能在單線程環(huán)境下,多線程環(huán)境下可以考慮用collections.synchronizedList(List l)函數(shù)返回一個線程安全的ArrayList類,也可以使用concurrent并發(fā)包下的CopyOnWriteArrayList類。
LinkedList同樣是非線程安全的,只在單線程下適合使用,使用迭代器都會快速失敗。
LinkedList和ArrayList實現(xiàn)了Serializable接口,因此它支持序列化,能夠通過序列化傳輸,實現(xiàn)了Cloneable接口,能被克隆。
ArrayList實現(xiàn)了RandomAccess接口,支持快速隨機訪問而LinkedList不支持快速隨機訪問,但是用LinkedList中的Node node(int index)訪問方法進行訪問時,會先判斷index是否大于LinkedList長度的一半,如果大于就從尾部往前遍歷,如果小于就從頭部往后遍歷。這樣一來如果index處在靠近頭部或是尾部時訪問時間就會小很多。
除了實現(xiàn)List接口外,LinkedList類還為在列表的開頭及結(jié)尾get、remove和insert元素提供了統(tǒng)一的命名方法。這些操作允許將鏈接列表用作堆棧、隊列或雙端隊列。此類實現(xiàn)Deque接口,為add、poll提供先進先出隊列操作,以及其他堆棧和雙端隊列操作。