前言程序員
ArrayList想必是廣大Java程序員開發時最經常使用的數據結構了,但不必定對其原理都有了解,今天我將結合ArrayList的源碼對其進行講解。本文將圍繞ArrayList主要特性(包括適用場景、初始大小、擴容等)、數據存放方式、核心方法實現、其餘特性等四個方面進行講解。面試
1、ArrayList特性數組
ArrayList是基於數組的數據結構,與LinkedList相比,更加適合在查詢多、增刪操做少的場景下使用,而且它是非線程安全的,若是併發量比較大的場景,須要改用線程安全的版本或者用JUC包中的CopyOnWriteArrayList。安全
它的初始數組大小爲10,由下圖所示的成員變量控制:數據結構
當新加元素時原數組已經滿了,則會觸發擴容,擴容策略爲將原數組長度*1.5,代碼中是用右移位運算實現的,源碼以下所示:多線程
2、數據存放方式併發
ArrayList是以數組的方式存放數據的,Object[],以下所示:this
3、核心方法實現spa
咱們看最經常使用的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方法實現的數組複製。其餘方法更加簡單,此處就不一一粘貼源碼解讀了。
4、其餘特性
一、關於modCount
在看ArrayList源碼的時候,會發現有一個變量是modCount,在增刪改的方法中均涉及到對它的++操做。modCount屬性是在AbstractList中定義出來的:
能夠把它理解成每一個ArrayList的一個改動的版本號,只要ArrayList有改動,這個版本號就會+1。在經過迭代器對ArrayList裏面的元素進行遍歷操做時,每次都會比較一下這個版本號是否有變化,若是檢測到預期以外的變化,就會拋出常見的那個異常-ConcurrentModificationException:
ArrayList東西很少,實現也相對比較簡單,面試時如今通常會跟Vector或者LinkedList進行比對或者做爲多線程的一個引子來問,本文就先到這裏,下一期對LinkedList進行解讀。