- 定義
- java.util.ArrayList類就是傳說中的動態數組,相當於Array的複雜版本,也就是說,ArrayList對象既有數組的特徵,也有列表的特徵。ArrayList實現了List接口,允許對元素進行快速隨機訪問。
- 結構
- 源碼
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
// 默認大小
private static final int DEFAULT_CAPACITY = 10;
// 共享的空數組,用於初始化空實例
private static final Object[] EMPTY_ELEMENTDATA = {};
//主要作爲一個標識位,在擴容時區分:默認大小和容量爲0,使用默認容量時採取的是“懶加載”
//即等到add元素的時候才進行實際容量的分配
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//ArrayList內部結構,是一個Object[]類型的數組
transient Object[] elementData;
//記錄當前容器中有多少元素
private int size;
- DEFAULT_CAPACITY :默認大小爲 10;(擴容爲原來的一半 擴容一次以後爲15)擴容使用Arrays.copyOf(elementData, size, Object[].class);
- EMPTY_ELEMENTDATA: 共享的空數組,用於初始化空實例
- Object[] elementData:ArrayList內部結構,是一個Object[]類型的數組
- size:記錄當前容器中有多少元素
- 構造方法
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
//無參構造器,指向的是默認容量大小的Object數組,注意使用無參構造函數的時候並沒有直接創建容量
//爲10的Object數組,而是採取懶加載的策略:使用DEFAULTCAPACITY_EMPTY_ELEMENTDATA(實際容量爲0)
//作爲標識,在真正add元素時纔會開闢Object數組,即在擴容函數中有處理默認容量的邏輯,後面會有分析
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
1. public ArrayList(int initialCapacity) 構造方法:表示接受指定容量值,初始化創建數組,真正開發時候按照實際情況創建ArrayList可指定。
2. public ArrayList() 構造方法:是默認的構造方法,它創建一個空數組。
3. public ArrayList(Collection<? extends E> c) 構造方法:接收一個Collection的實體,將該Collection實體轉換爲ArrayList對象。
- add 添加方法
public boolean add(E e) {
modCount++;
//add操作的核心函數,當使用無參構造器時並沒有直接分配大小爲10的Object數組,這裏面有對應
//的處理邏輯
add(e, elementData, size);
return true;
}
- 主要用於標識線程安全,即ArrayList只能在單線程環境下使用,在多線程環境下會出現併發安全問題,modCount主要用於記錄對ArrayList的修改次數,如果一個線程操作期間modCount發生了變化即,有多個線程同時修改當前這個ArrayList,此時會拋出“ConcurrentModificationException”異常,這又被稱爲“failFast機制”,在很多非線程安全的類中都有failFast機制:HashMap、 LinkedList等。這個機制主要用於迭代器、加強for循環等相關功能,也就是一個線程在迭代一個容器 時,如果其他線程改變了容器內的元素,迭代的這個線程會拋出“ConcurrentModificationException”異常
-
LinkedList底層採用雙向列表實現,所以在添加新元素的時候要先構造一個Node對象(item爲我們加入的值),只需要將Node的next賦值爲新的Node即可。但是相對於ArrayList而言,LinkedList可以更加高效的插入元素,因爲它不會涉及到ArrayList擴容。但也因爲這種數據結構,導致它不具備有隨機訪問的能力。
-
ArrayList和LinkedList都不是線程安全的。那麼如果我們要用線程安全的用什麼呢 ?
- List list = Collections.synchronizedList(new ArrayList<>());Collections提供了方法synchronizedList保證list是同步線程安全的。
- CopyOnWriteArrayList:寫時複製,CopyOnWrite容器既寫時複製的容器,往一個容器添加元素的時候,不直接往當前的容器Object[]添加,而是先將當前容器Object[] 進行Copy,複製出一個新的容器Object[] newElements,然後往新的容器Object[] newElement裏面添加元素,添加完元素之後,再將原容器的引用指向新的容器,setArray(newElements );這樣做的好處是可以對CopyOnWriter容器進行併發的讀,而不需要加鎖,因爲當前容器不會添加任何元素,所以CopyOnWrite容器也是一種讀寫分離的思想,讀和寫不同的容器。
public boolean add(E e) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1); newElements[len] = e; setArray(newElements); return true; } finally { lock.unlock(); } }
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-gCSSDd7N-1585494592841)(https://upload-images.jianshu.io/upload_images/8123471-3db0a888e48cd3a2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]