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就出來了,得益於它底層的鍊錶結構...