原始碼解析java集合框架,ArrayList原始碼

2021-09-12 22:15:04 字數 3576 閱讀 6206

arraylist是list介面下的乙個實現類,arraylist是乙個動態陣列,底層資料結構為可以動態增長的陣列,相比陣列來說,arraylist可以動態的增加刪除元素,有成熟的擴容演算法。

如圖,為arraylist資料結構,是乙個記憶體連續且緊湊的陣列。arraylist訪問元素時間複雜度為o(1),插入、刪除需要移動大量元素,時間複雜度為o(n),arraylist適合儲存及訪問資料,不適合操作頻繁的資料儲存。

arraylist非執行緒安全,多執行緒中不能使用arraylist,可使用vector。

1、構造方法

1.1 無參構造方法

public arraylist()
無參構造方法,裡面只有乙個賦值操作,把 defaultcapacity_empty_elementdata 賦值給elementdata,我們來看看它們都是什麼:

transient object elementdata; // non-private to simplify nested class access

private static final object defaultcapacity_empty_elementdata = {};

elementdata 是乙個object陣列,用來儲存arraylist元素,可見,arraylist底層就是乙個動態陣列。

defaultcapacity_empty_elementdata 是乙個空陣列,所以,呼叫無參構造方式只是新建乙個空object陣列。

1.2 有參構造方法

public arraylist(int initialcapacity)  else if (initialcapacity == 0)  else 

}

傳入初始容量引數的構造方法,引數為整形,代表初始化object陣列長度。可以看到,當引數為0時,同樣給 elementdata 賦值了乙個空object陣列。當大於0時,新建相應長度的陣列。

2、arraylist的新增元素方法

2.1 public boolean add(e e)

public boolean add(e e)
傳入需要新增的元素e,elementdata[size++] = e 把元素放置陣列size++位置,緊接在後面。

ensurecapacityinternal(size + 1); 為arraylist擴容,擴容是arraylist中尤為重要且相對複雜的部分。

private void ensurecapacityinternal(int mincapacity) 

private static int calculatecapacity(object elementdata, int mincapacity)

return mincapacity;

}/** default initial capacity. */

private static final int default_capacity = 10;

calculatecapacity() 方法傳入了新增元素後的容量mincapacity,也就是size++,和當前object陣列elementdata。先判斷elementdata是否為空,如果為空則返回mincapacity與default_capacity中較大者,default_capacity是arraylist初始化最小的容量,default_capacity值為10,所以,arraylist的容量最小為10。

再來看ensureexplicitcapacity()方法:

protected transient int modcount = 0;

private void ensureexplicitcapacity(int mincapacity)

ensureexplicitcapacity()方法傳入了mincapacity與default_capacity比較之後的值,先是做判斷,如果當前陣列長度不夠,則呼叫grow()方法擴容,如果足夠則不擴容。

private void grow(int mincapacity)
grow()方法是arraylist真正擴容方法,oldcapacity >> 1 位移運算,相當於oldcapacity * 0.5,所以擴容後新的容量為1.5倍,每次增長0.5倍,最後使用arrays工具類構建新的容量更大的陣列。

2.2 public void add(int index, e element)

這個add()方法傳入了兩個引數,乙個是所增加的元素,和新元素插入的位置索引index。

public void add(int index, e element)
首先對index索引位置檢驗,不能超過陣列長度,不能傳負數,否則拋異常。

然後以同樣的方式1.5倍擴容,再使用本地native方法system.arraycopy()把index後所有元素向後移動1,再把element元素插入到index位置,陣列長度加1,相對上乙個add()方法多了乙個移動元素操作,很大可能需要移動大量元素,時間複雜度增加o(n)。

擴容機制小結

如果arraylist初始化沒指定容量,則最初arraylist為空的陣列,新增元素後初始化容量為10,當容量不夠了每次增加0.5倍。

如果初始化指定容量則新建相應長度的資料,再往裡新增元素,容量不夠再每次增加0.5倍。

3、arraylist的獲取元素方法get(index)

public e get(int index)
獲取元素方法很簡單,先對索引位置檢驗,是否超出陣列長度,否則拋異常outofindex。

然後直接返回相應位置的元素,獲取操作非常簡便,時間複雜度很低,效能高。

4、arraylist的移除元素方法remove(index)、remove(object)

public e remove(int index)
方法返回的是所移除的元素,同樣還是使用system.arraycopy()大量向前移動元素。

public boolean remove(object o) 

} else

}return false;

}

這個方法傳入的是要刪除的元素值,思路是根據元素值匹配到元素所在的索引位置index,再向前移動後面的元素。

可見,移除元素同樣需要移動大量的元素,時間複雜度大。

後語,arraylist底層就是物件陣列,新增和移除元需要移動大量元素,效率低。相反,查詢操作效率十分高,只需返回對應索引的元素。

arraylist適合存放查詢資料,不適合有刪減改動的資料。

Java集合之 Map原始碼解析

hashmap 也是我們平時開發中使用頻率很高的雙列集合,直接父類是abstractmap,是基於hash表儲存的一種集合。幾個重要的類變數 hash表的初始化大小,預設為16.是基於陣列實現的。static final int default initial capacity 1 4 aka 16...

java 集合框架 迭代器的原理及原始碼解析

a 迭代器原理 迭代器原理 迭代器是對集合進行遍歷,而每乙個集合內部的儲存結構都是不同的,所以每乙個集合存和取都是不一樣,那麼就需要在每乙個類中定義hasnext 和next 方法,這樣做是可以的,但是會讓整個集合體系過於臃腫,迭代器是將這樣的方法向上抽取出介面,然後在每個類的內部,定義自己迭代方式...

集合 LinkedList原始碼解析

在實際開發中,arraylist的使用頻率是最高的,因為多數情況下我們使用arraylist容器儲存資料,以便在後面做遍歷,或者做查詢操作,此時用arraylist確實是最恰當的。然而有些場景,我們可能會經常性的對容器裡的元素進行變更,那麼這個時候linkedlist就出來了,得益於它底層的鍊錶結構...