前言
ArrayList想必是廣大Java程序員開發時最常用的數據結構了,但不一定對其原理都有了解,今天我將結合ArrayList的源碼對其進行講解。本文將圍繞ArrayList主要特性(包括適用場景、初始大小、擴容等)、數據存放方式、核心方法實現、其他特性等四個方面進行講解。
一、ArrayList特性
ArrayList是基於數組的數據結構,與LinkedList相比,更加適合在查詢多、增刪操作少的場景下使用,並且它是非線程安全的,如果並發量比較大的場景,需要改用線程安全的版本或者用JUC包中的CopyOnWriteArrayList。
它的初始數組大小為10,由下圖所示的成員變量控制:
當新加元素時原數組已經滿了,則會觸發擴容,擴容策略為將原數組長度*1.5,代碼中是用右移位運算實現的,源碼如下所示:
二、數據存放方式
ArrayList是以數組的方式存放數據的,Object[],如下所示:
三、核心方法實現
我們看最常用的add方法:
1 public boolean add(E e) { 2 ensureCapacityInternal(size + 1); // 如果已經滿了,則擴容 3 elementData[size++] = e; 4 return true; 5 }
下面方法用於判斷是否原數組已經滿了,如果滿了則擴容,不滿且未初始化則初始化長度為10,否則不用變化
1 private void ensureCapacityInternal(int minCapacity) { 2 ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); 3 }
下面方法用於返回數組需要的最小長度。
1 private static int calculateCapacity(Object[] elementData, int minCapacity) { 2 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { 3 return Math.max(DEFAULT_CAPACITY, minCapacity); 4 } 5 return minCapacity; 6 }
下面的方法用於判斷是否需要擴容,如果需要則通過grow方法擴容。
1 private void ensureExplicitCapacity(int minCapacity) { 2 modCount++; 3 4 // overflow-conscious code 5 if (minCapacity - elementData.length > 0) // 如果需要的最小長度大於當前數組總長度,則走grow擴容 6 grow(minCapacity); 7 }
下面的grow方法是控制擴容的核心方法:
1 private void grow(int minCapacity) { 2 // overflow-conscious code 3 int oldCapacity = elementData.length; 4 int newCapacity = oldCapacity + (oldCapacity >> 1); 5 if (newCapacity - minCapacity < 0) // 如果擴容之后的長度小於需要的最小長度,則取最小長度為待擴容長度,這種情況一般不會出現 6 newCapacity = minCapacity; 7 if (newCapacity - MAX_ARRAY_SIZE > 0) 8 newCapacity = hugeCapacity(minCapacity); 9 // minCapacity is usually close to size, so this is a win: 10 elementData = Arrays.copyOf(elementData, newCapacity); // 創建新數組,將老數組的數據復制過去 11 }
注意復制數組時,用的Arrays.copyOf方法,該方法最終引用的是System.arraycopy這個native方法實現的數組復制。其他方法更加簡單,此處就不一一粘貼源碼解讀了。
四、其他特性
1、關於modCount
在看ArrayList源碼的時候,會發現有一個變量是modCount,在增刪改的方法中均涉及到對它的++操作。modCount屬性是在AbstractList中定義出來的:
可以把它理解成每個ArrayList的一個改動的版本號,只要ArrayList有改動,這個版本號就會+1。在通過迭代器對ArrayList里面的元素進行遍歷操作時,每次都會比較一下這個版本號是否有變化,如果檢測到預期之外的變化,就會拋出常見的那個異常-ConcurrentModificationException:
ArrayList東西不多,實現也相對比較簡單,面試時現在一般會跟Vector或者LinkedList進行比對或者作為多線程的一個引子來問,本文就先到這里,下一期對LinkedList進行解讀。