ArrayList分析
對于集合的源碼分析,一般我會采用這幾種方式
話不多說,直接走起。
一.怎么添加元素?
一般我們通過ArrayList添加元素。一般會調用其構造方法,然后調用其對象的add方法
查看空參構造函數
//Constructs an empty list with an initial capacity of ten.public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;} 復制代碼通過構造函數可以發現。ArrayList在調用無參的構造函數時,會構造一個長度為10的緩存數組
查看add方法
public boolean add(E e) {ensureCapacityInternal(size + 1); elementData[size++] = e;return true;} 復制代碼通過該方法發現 ArralyList內部的數據結構其實是一個數組(elementData[size++] = e;)并且在添加時會先判斷當前容器在添加了一個對象之后該對象的容納能力(主要為了,在下一次添加元素的時候,緩存數組能夠有足夠的空間添加元素)。之后將元素添加到數組末尾。
繼續查看ensureCapacityInternal()方法
private void ensureCapacityInternal(int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}ensureExplicitCapacity(minCapacity);} 復制代碼這里我們發現,如果當前elementData為空的話,minCapacity=DEFAULT_CAPACITY,同時DEFAULT_CAPACITY的默認值是10,從這我們可以看出,在第一次初始化的時候,ArrayList內部會默認創建一個內部長度為10的數組。
繼續點擊ensureExplicitCapacity()方法
private void ensureExplicitCapacity(int minCapacity) {modCount++;//判斷添加元素后,緩存數組時候需要擴展if (minCapacity - elementData.length > 0)grow(minCapacity);} 復制代碼該方法會記錄當前數組的更改次數,并且判斷當前數組添加后,是否需要進行增長,
繼續走grow方法(重點的來了!!!)
private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;//擴展數組的長度,int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);} 復制代碼該方法會擴展緩存為當前數組的長度為 原數組長度+原數組長度的二分之一,也就是按照原數組的50%進行增長,同時該數組最大的擴展長度是Integer.MAX_VALUE - 8。也就是ArrayList最多能存儲的數據長度,通過擴展數組長度以后,在下一次添加數據的時候,ArrayList就有足夠的空間去添加新的元素了。
二.怎么獲取元素
其實ArrayList獲取其中的元素很簡單,根據角標獲取對應數組中的元素,具體代碼如下:
public E get(int index) {if (index >= size)//判斷當前角標長度是否超過數組長度,如果是拋出異常,反之返回數據throw new IndexOutOfBoundsException(outOfBoundsMsg(index));return (E) elementData[index];}復制代碼##三.怎么刪除元素 在ArrayList中,有兩個關于刪除元素的方法,一個是remove(int),另一個是remove(Object)
1.remove(int)方法
public E remove(int index) {if (index >= size)throw new IndexOutOfBoundsException(outOfBoundsMsg(index));modCount++;E oldValue = (E) elementData[index];int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; // 將數組最后一位置nullreturn oldValue;} 復制代碼這里先判斷刪除角標是否超過數組長度,然后通過System.arrayCopty()方法將角標對應的元素刪除。
這里對System.arrayCopty()方法解釋一下。該方法的第一個參數是源數組,第二個參數是復制的開始角標,第二個參數是目標數組。第三個參數是目標數組與源數組的復制數據開始角標。最后一個參數是復制的長度。(注意:!!!復制的長度不能大于目標數組減去開始角標的長度或源數組減去開始角標的長度)
eg:
int[] a = {0, 1, 2, 3, 4};int[] b = {5, 6, 7, 8, 9};System.arraycopy(a, 0, b, 1, 3);// 則進行操作后 b = {5,0,1,2,9} 復制代碼2.remove(Object)方法
public boolean remove(Object o) {if (o == null) {//判斷當前元素是否為空,遍歷數組,獲取其角標for (int index = 0; index < size; index++)if (elementData[index] == null) {fastRemove(index);return true;}} else {for (int index = 0; index < size; index++)if (o.equals(elementData[index])) {fastRemove(index);return true;}}return false;}private void fastRemove(int index) {//根據角標,刪除相應元素modCount++;int numMoved = size - index - 1;if (numMoved > 0)System.arraycopy(elementData, index+1, elementData, index,numMoved);elementData[--size] = null; // clear to let GC do its work} 復制代碼remove(Object)根據object在數組的角標,執行fastRemove(index)方法。刪除方法與remoIndex(int)一樣。這里就不在分析了。
總結
- ArrayList內部實現是數組,且當數組長度不夠時,數組的會進行原數組長度的1.5倍擴容。
- ArrayList內部元素是可以重復的。且有序的,因為是按照數組一個一個進行添加的。
- ArrayList是線程不安全的,因為其內部添加、刪除、等操作,沒有進行同步操作。
- ArrayList增刪元素速度較慢,因為內部實現是數組,每次操作都會對數組進行復制操作,復制操作是比較耗時的
最后,附上我寫的一個基于Kotlin 仿開眼的項目SimpleEyes(ps: 其實在我之前,已經有很多小朋友開始仿這款應用了,但是我覺得要做就做好。所以我的項目和其他的人應該不同,不僅僅是簡單的一個應用。但是,但是。但是。重要的話說三遍。還在開發階段,不要打我),歡迎大家follow和start
總結
以上是生活随笔為你收集整理的ArrayList分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 国内勒索病毒疫情严重 每天十多万台电脑被
- 下一篇: 可穿戴计算之父:成都能成为可穿戴技术未来