Java 集合系列(二)—— ArrayList
ArrayList
ArrayList 是通過一個數組來實現的,因此它是在連續的儲存位置存放物件的引用,只不過它比 Array 更智慧,能夠根據集合長度進行自動擴容。
假設讓我們來實現一個簡單的能夠自動擴容的陣列,我們最容易想到的點就是:
- add()的時候需要判斷當前陣列size+1是否等於此時定義的陣列大小;
- 若小於直接新增即可;否則,需要先擴容再進行新增。
實際上,ArrayList的內部實現原理也是這樣子,我們可以來研究分析一下ArrayList的原始碼
add(E e)
原始碼分析
1/** 2* Appends the specified element to the end of this list. 3* 4* @param e element to be appended to this list 5* @return <tt>true</tt> (as specified by {@link Collection#add}) 6*/ 7public boolean add(E e) { 8ensureCapacityInternal(size + 1);// 進行擴容校驗 9elementData[size++] = e;// 將值新增到陣列後面,並將 size+1 10return true; 11} 12 13 14 15/** 16* The array buffer into which the elements of the ArrayList are stored. 17* The capacity of the ArrayList is the length of this array buffer. Any 18* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 19* will be expanded to DEFAULT_CAPACITY when the first element is added. 20*/ 21transient Object[] elementData; // non-private to simplify nested class access 22 23private void ensureCapacityInternal(int minCapacity) { 24ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));// elementData 陣列 25} 26 27 28 29/** 30* Default initial capacity. 31*/ 32private static final int DEFAULT_CAPACITY = 10; 33 34/** 35* Shared empty array instance used for default sized empty instances. We 36* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when 37* first element is added. 38*/ 39private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; 40 41// 返回最大的 index 42private static int calculateCapacity(Object[] elementData, int minCapacity) { 43if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//與空陣列例項對比 44return Math.max(DEFAULT_CAPACITY, minCapacity); 45} 46return minCapacity; 47} 48 49 50 51private void ensureExplicitCapacity(int minCapacity) { 52modCount++; 53 54// overflow-conscious code 55if (minCapacity - elementData.length > 0) 56grow(minCapacity); 57}
擴容呼叫方法,實際也就是陣列複製的過程
1/** 2* Increases the capacity to ensure that it can hold at least the 3* number of elements specified by the minimum capacity argument. 4* 5* @param minCapacity the desired minimum capacity 6*/ 7private void grow(int minCapacity) { 8// overflow-conscious code 9int oldCapacity = elementData.length; 10int newCapacity = oldCapacity + (oldCapacity >> 1); 11if (newCapacity - minCapacity < 0) 12newCapacity = minCapacity; 13if (newCapacity - MAX_ARRAY_SIZE > 0) 14newCapacity = hugeCapacity(minCapacity); 15// minCapacity is usually close to size, so this is a win: 16elementData = Arrays.copyOf(elementData, newCapacity); 17}
add(int index, E element)
原始碼分析
1/** 2* Inserts the specified element at the specified position in this 3* list. Shifts the element currently at that position (if any) and 4* any subsequent elements to the right (adds one to their indices). 5* 6* @param index index at which the specified element is to be inserted 7* @param element element to be inserted 8* @throws IndexOutOfBoundsException {@inheritDoc} 9*/ 10public void add(int index, E element) { 11rangeCheckForAdd(index);// 校驗index是否超過當前定義的陣列大小範圍,超過則丟擲 IndexOutOfBoundsException 12 13ensureCapacityInternal(size + 1);// Increments modCount!! 14System.arraycopy(elementData, index, elementData, index + 1, 15size - index);// 複製,向後移動 16elementData[index] = element; 17size++; 18} 19 20 21/** 22* A version of rangeCheck used by add and addAll. 23*/ 24private void rangeCheckForAdd(int index) { 25if (index > size || index < 0) 26throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); 27}
從上面的原始碼分析可知,擴容和隨機插入元素的消耗比較大,因此在實際開發中,應儘量指定ArrayList大小,減少在隨機插入操作。
優缺點
優點
- 封裝了一個動態再分配的物件陣列
- 使用索引進行隨機訪問效率高
缺陷
- 在陣列中增刪一個元素,所有元素都要往後往前移動,效率低下
知識腦圖
在 github 上建了一個 repository ,Java Core Knowledge Tree,各位看官若是喜歡請給個star,以示鼓勵,謝謝。
https://github.com/suifeng412/JCKTree(以上是自己的一些見解,若有不足或者錯誤的地方請各位指出)
作者:那一葉隨風 http://www.cnblogs.com/phpstudy2015-6/
原文地址: https://www.cnblogs.com/phpstudy2015-6/p/10618707.html
宣告:本部落格文章為原創,只代表本人在工作學習中某一時間內總結的觀點或結論。轉載時請在文章頁面明顯位置給出原文連結