ArrayList底层实现原理「建议收藏」
ArrayList簡介
ArrayList是我們開發中非常常用的數據存儲容器之一,其底層是數組實現的,我們可以在集合中存儲任意類型的數據,ArrayList是線程不安全的,非常適合用于對元素進行查找,效率非常高。
源碼分析
創建了一個大小為0的數組,在后面會用到。
聲明了一個數組。
ArrayList的無參構造方法,將前面聲明創建的大小為0的數組賦給elementData數組。
這是ArrayList的有參構造方法,傳入一個int類型的變量,相當于我們在使用arrayList的時候指定list的大小。
如果傳入的參數大于0,則新建一個initialCapacity大小的數組。
傳入值等于0的話,將這個空數組給elementData。
下面我們來看add()方法的源碼:
使用到了一個size的參數,先看ensureCapacityInternal方法。
size參數在前面進行了聲明,作用是標識該數組的大小的。
先執行了calculateCapacity方法,將數組和原先數組大小+1的數值傳入。
對數組進行判斷,判斷該數組是否為空,
,這是一個空的數組,在前面聲明過,如果現存的數組等于空的,我們就返回一個數值,
,第一個變量是常量10,第二個是我們前面傳入進來的,比較它倆的大小,返回大的數值。
如果不為空的話,我么直接返回前面方法傳入的數值。進入ensureExplicitCapacity()方法。
modCount是前面聲明的變量,初始值為0。
首先進行判斷,如果新長度減去數組原先的長度大于0,我們則調用grow方法,并將新長度傳入進去。
這里就是ArrayList底層數組擴容的核心代碼。
新長度是舊長度加上舊長度的0.5,所以ArrayList底層數組每次擴容的大小都是1.5倍。
第一個if,如果新創建的長度小于傳入的數組長度,那么就更新newCapacity的值為minCapacity。
第二個if,如果新數組長度減去最大的數組長度大于0的話,會進入hugeCapacity再次進行判斷,返回Integer的最大長度,或者Integer的最大長度-8的長度。
之后完成數組復制,至此,ArrayList的底層擴容已經實現。
添加的方法說完了,下面我們來看看刪除的方法。
刪除是每次進行數組復制,然后讓舊的elementData置為null進行垃圾回收,代碼很簡單,一看就懂,但是我們可以從源碼中去發現使用技巧。
查詢的方法就更簡單了,直接返回查詢的對應數組中的值。
下面我們來自己寫一個簡易的ArrayListDemo。
/** * 作者:LKP * 時間:2018/7/13 */
public class ArrayListDemo {
private Object[] arry; //數組
private int size = 0; //下標
public ArrayListDemo(){
this.arry = new Object[10];
}
public ArrayListDemo(int size) throws Exception {
if(size > 0)
this.arry = new Object[size];
else
throw new Exception("長度不允許小于零!");
}
//新增
public void add(Object number){
if(size >= arry.length){
int length = arry.length;
Object[] newArry = new Object[length];
for(int i=0; i<arry.length; i++){
newArry[i] = arry[i];
}
length = (length*3)/2+1; //更新數組長度
arry = new Object[length]; //對原有數組進行擴容
for(int j=0; j<newArry.length; j++){
arry[j] = newArry[j];
}
newArry = null; //釋放該數組
}
arry[size] = number;
size++;
}
//讀取
public Object get(int index) throws Exception {
if(index >= 0)
return arry[index];
throw new Exception("下標不符合要求!");
}
//獲得大小
public int getSize(){
int count = 0;
for(int i=0; i<arry.length; i++){
if(arry[i] != null){
count++;
}
}
return count;
}
}
客戶端代碼:
/** * 作者:LKP * 時間:2018/7/13 */
public class demo {
public static void main(String[] args){
ArrayList ls = new ArrayList();
ArrayListDemo list = new ArrayListDemo();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
for(int i=0; i<list.getSize(); i++) {
try {
System.out.println("List的值:"+list.get(i));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
運行結果:
總結
1.在聲明時盡量指定長度。
2.ArrayList底層是數組,數組是適合查詢的,因為數組每個元素的內存空間是固定的,每次查詢時,只需要去查詢對應位置的內存空間,就可以很快找到相應的值。而數組不擅長的是添加和刪除。試想,集合長度是100000,而我們在第2個位置添加了一個元素,導致的結果是從第3個開始后面每一個元素都要往后串一個元素內存空間那么大的位置。刪除剛好相反,是向前串一個位置,這樣的效率是很低的,元素越多,效率越低。而頻繁的添加和刪除,適用鏈表——LinkedList。
總結
以上是生活随笔為你收集整理的ArrayList底层实现原理「建议收藏」的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图论--LCA--Tarjan(离线)
- 下一篇: 图论--最短路--Floyd(含路径输出