在Java中,list是我們常用的數(shù)據(jù)結構犀被,一般我們都知道list根據(jù)底層數(shù)據(jù)結構的不同分為兩種類型厕倍,分別是數(shù)組對應的ArrayList和鏈表對應的LinkedList,其特性從底層數(shù)據(jù)結構的不同可以很容易的被我們聯(lián)想到尚氛,大致來說可以分為以下幾個方向
- 插入和刪除操作的效率:ArrayList在末尾進行插入和刪除操作時效率較高诀诊,因為它可以直接通過下標訪問元素。但是在中間或開頭進行插入和刪除操作時阅嘶,需要移動后續(xù)元素属瓣,效率較低。而LinkedList在任意位置進行插入和刪除操作時效率較高讯柔,因為只需要改變前后節(jié)點的指針即可抡蛙。
- 隨機訪問的效率:ArrayList可以通過下標直接訪問元素,因此在隨機訪問時效率較高魂迄。而LinkedList需要從頭或尾開始遍歷鏈表粗截,直到找到目標位置,因此在隨機訪問時效率較低捣炬。
- 內(nèi)存占用:ArrayList每個元素需要額外的空間存儲下標信息熊昌,因此在存儲大量元素時占用的內(nèi)存更大绽榛。而LinkedList每個元素需要額外的空間存儲前后節(jié)點的指針,因此在存儲大量元素時占用的內(nèi)存較小婿屹。
但是很多人不知道在Java中使用list集合還有很多需要注意的坑灭美,今天先在這里記錄幾點
我們常說的list是指
java.util.List
包下的,而在java.util.Arrays
包下也有一個ArrayList选泻,常見于Arrays.asList
方法返回冲粤,也就是說我們常用的數(shù)組轉list的方法返回的是java.util.Arrays
包下的list,這是Arrays類里面的一個靜態(tài)內(nèi)部類页眯,它和我們常用的ArrayList一樣繼承了AbstractList
梯捕,使用上需要注意的是Arrays的靜態(tài)內(nèi)部類是沒有提供add、remove方法的窝撵,所以如果我們利用上述方法進行數(shù)組轉list的話只能執(zhí)行get操作-
list.subList方法的使用傀顾。此方法返回的是原始list的一個子列表視圖,本質(zhì)上是AbstractList的一個內(nèi)部類碌奉,其依然保存有原始列表的結構短曾,如果對這個視圖進行修改的話也會影響到原始列表,并且其add方法是會將數(shù)據(jù)加到最源頭的list上赐劣,看到這里敏感的朋友應該能意識到可能會出現(xiàn)什么問題了
- 如果這種指代關系太深的話嫉拐,那么就有可能會出現(xiàn)StackOverflowError
- 當你拿到的這個list只有幾個元素,但其實它所指向的parent列表可能會遠遠超出你的想象魁兼,由此導致內(nèi)存泄漏
-
ArrayList和LinkedList在不同垃圾回收算法下的表現(xiàn)
- 標記-清除算法:標記-清除算法通常會遍歷整個內(nèi)存堆婉徘,標記所有活動對象,然后清除未被標記的對象咐汞。在這種情況下盖呼,ArrayList和LinkedList的表現(xiàn)可能相似,因為它們都只是對象的集合化撕,垃圾回收器會以相似的方式處理它們几晤。
- 復制算法:復制算法將內(nèi)存堆分為兩個區(qū)域,每次只使用其中一個區(qū)域植阴⌒否活動對象被復制到另一個區(qū)域,然后清除當前區(qū)域中的所有對象掠手。在這種情況下热芹,ArrayList和LinkedList的表現(xiàn)可能有所不同。由于ArrayList使用連續(xù)的內(nèi)存塊存儲元素惨撇,復制大型ArrayList可能會更耗時,因為需要復制整個連續(xù)塊府寒。而LinkedList使用鏈表結構魁衙,每個節(jié)點可以被單獨復制报腔,因此在復制算法下,LinkedList可能更高效剖淀。
- 標記-整理算法:標記-整理算法將存活對象向一端移動纯蛾,然后清除剩余部分。在這種情況下纵隔,ArrayList和LinkedList的表現(xiàn)可能相似翻诉,因為它們都只是對象的集合,垃圾回收器會以相似的方式處理它們捌刮。