List
接口的可調節大小的數組實現。它實現了三個接口,相同點都是空接口,做爲一個標記出現。java
類的序列化由實現這個接口的類啓動。不實現此接口的類不會使用任何狀態序列化和反序列化。數組
序列化:將對象的數據寫入到文件安全
反序列化:將文件中的對象的數據讀取出來數據結構
只有實現這個 「可克隆」 接口,而後在類中重寫 Object 中的 clone()
方法,後面經過類調用 clone 方法才能克隆成功。若是不實現這個接口,則會拋出 克隆不被支持 的異常。併發
只要實現了這個接口,就能支持快速隨機訪問。dom
- ArrayList 實現了 RandomAccess 接口,使用 for 循環經過索引遍歷。
- LinkedList 沒有實現這個接口,默認使用 iterator 進行遍歷。
經過測試,他們這樣各自的實現是最高效的,因此實現 RandomAccess 接口也須要根據實際場景需求來進行。工具
構造方法 | 描述 |
---|---|
ArrayList() | 構造一個初始容量爲 10 的空列表 |
ArrayList(int initialCapacity) | 構造一個指定初始容量的空列表 |
ArrayList(Collection<? extends E> c) | 構造一個包含指定集合元素的列表(參數就是一個集合) |
方法 | 時間複雜度 |
---|---|
add(E e) | 添加元素到末尾,平均時間複雜度爲O(1) |
add(int index, E e) | 添加元素到指定位置,平均時間複雜度爲O(n) |
get(int index) | 獲取指定索引位置的元素,時間複雜度爲O(1) |
remove(int index) | 刪除指定索引位置的元素,時間複雜度爲O(n) |
remove(Object o) | 刪除指定元素值的元素,時間複雜度爲O(n) |
public boolean add(E e) { //調用方法對內部容量進行檢查 ensureCapacityInternal(size + 1); elementData[size++] = e; return true; } private void ensureCapacityInternal(int minCapacity) { //若是 elementData 數組爲空 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //若是容量不足10,擴容至默認容量10(第一次擴容的參數,此時數組還爲null) minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); //將上面計算出的容量傳遞,繼續檢查 } private void ensureExplicitCapacity(int minCapacity) { modCount++; //記錄修改的次數++ (主要用於迭代器中) //當前最小容量 - 數組長度 > 0(判斷是否溢出) if (minCapacity - elementData.length > 0) //將第一次計算出來的容量傳給 「核心擴容方法」 grow(minCapacity); }
private void grow(int minCapacity) { int oldCapacity = elementData.length; //記錄舊的數組容量 int newCapacity = oldCapacity + (oldCapacity >> 1); //新容量擴容1.5倍 //若是新容量小於最小容量,則將最小容量的值賦給 新容量(若是是第一次調用add方法必然小於) if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //若是newCapacity大於數組最大容量(默認是int類型最大值) if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); //建立超大數組,Integer.MAX_VALUE //建立一個新數組,將新數組的地址賦值給elementData elementData = Arrays.copyOf(elementData, newCapacity); }
建立集合的時候指定足夠大的容量。源碼分析
ArrayList 不是線程安全的,例如當咱們 add 操做時,elementData[size++]
這個操做並非原子操做。性能
transient
關鍵字修飾的對象不會被序列化。由於 elementData
是 ArrayList 的數據域,因爲 ArrayList 是基於動態數組實現的, elementData
的容量一般大於實際存儲元素的容量,因此只需發送有實際值的數組元素便可。測試
數據結構:ArrayList底層是數組(內存裏是連續的空間),LinkedList底層鏈表(內存空間不連續)。
訪問效率:ArrayList
比LinkedList
在隨機訪問的時候效率要高,由於 LinkedList
是線性的數據存儲方式,因此須要移動指針從前日後依次查找。
增刪效率:LinkedList
要比 ArrayList
效率要高,由於 ArrayList
增刪操做要影響數組內的其餘數據的下標。LinkedList
只須要改變先後的指針就能夠了。
ArrayList 和 Vector的底層都是基於數組實現的動態擴容。他們的區別在於:
線程安全:Vector 使用了 Synchronized 來實現線程同步,而 ArrayList 是線程不安全的。
性能:ArrayList 在性能方面優於 Vector。
擴容:Vector 擴容每次擴容 2 倍,而 ArrayList 擴容 1.5 倍。
ArrayList和LinkedList的區別和原理
Vector
,方法上添加了 Synchronized 來實現線程同步,但已經不推薦了。Collections.synchronizedList()
方法。CopyOnWriteArrayList
類建立集合。CopyOnWriteArray 容器是一個 寫時複製 的容器。
往一個容器添加元素的時候,不直接往當前容器的 Object[] 添加,而是先將當前容器 Object[] 進行復制,複製出一個新的容器。而後向新的容器裏添加元素,添加完元素以後,再將原容器的引用指向新的容器。
這樣作的好處是,能夠對 CopyOnWrite 容器進行併發的讀,而不須要加鎖,由於當前容器不會添加任何元素。因此 CopyOnWrite 容器是一種 「讀寫分離」 的思想,讀和寫是不一樣的容器。
缺點是每次寫入都要複製一個新的數組,會形成內存浪費,垃圾回收頻繁等,適合讀多寫少的場景。