ArrayList是什麼?
顫抖的小手敲開門ArrayList的大門,發現她竟然是Object[] elementData數組。
構造函數
我們在使用集合的時候都知道集合長度是隨着插入刪除變化的,而在創建數組時時需要指定長度的,那ArrayList是如何做到長度可變數組呢
我們發現ArrayList有兩個構造函數,一個無參(我們經常用)一個有參(傳入一個int值,這個int就是初始數組的長度)
無參構造會在我們插入數據時候默認數組長度爲10,當我們在創建時指定了長度,就是初始化數組的長度。
這裏有一個關鍵字transient,這個關鍵字的作用就是在序列化時忽略該變量,ArrayList是集成Serializable的可以序列化反序列化操作的。
add數據
我們在使用集合時可以無限的添加數據的,這默認長度10,ArrayList是如何做到擴容的
這10只是數組的長度,我們集合的長度是根據size變量來的,集合會在插入數據是size+1然後去和數據的長度比較,如果超出了最大容量,就會創建一個長度爲10+10/2(JDK8的操作)長度的數組,然後把原數組的內容複製到新數組中,這就完成了擴容。
ArrayList在添加一個數據時做了三件事:
- size+1是否在集合容量之內ensureCapacityInternal(English是不是很吊),其實就是判斷是否需要擴容;
- 數據添加到索引爲size+1這個位置;
- 返回true。
看源碼會知道,擴容就是擴大之前的容器長度向右移1位。大家也可能注意到默認分配的數組大小爲integer的最大值-8,這是因爲
一些vm在數組中保留一些頭字。嘗試分配較大的數組可能會導致OutOfMemory錯誤:請求的數組大小超過了虛擬機限制(百度翻譯- -)。
ArrayList又是如何在指定索引處添加數據呢
集合在指定index插入數據,首先會複製數組index開始到最後一個值的數據,然後在index+1位置開始放,騰出index的位置給新值插入,當然這裏面也要先判斷容量問題。(如下圖在3的位置插入一個新值)
remove刪除數據
我們知道在我們遍歷ArrayList的時候刪除數據會報錯java.util.ConcurrentModificationException ,why?
移除數據的操作也是copy指定位置+1之後的數組移動到指定位置,直接看圖說話。
這就也可解釋爲什麼遍歷時移除數據會報錯,5覆蓋了4的位置,那麼5就無法被遍歷到了。當然如果我們從大到小遍歷就不會出現這個問題了。
ArrayList在增刪時候需要去copy數據,如果超出最大數組長度還要去擴容什麼的,所以說ArrayList的增刪效率是低的。
ArrayList的內存連續性使其遍歷速度相對較快,所以查找就快。