天天看點

JDK1.8源碼(六)——java.util.ArrayList類

  arraylist元素是有序的,可重複。線程不安全的。底層維護一個 object 數組。

  jdk1.7:arraylist像餓漢式,預設初始長度直接建立一個容量為 10 的數組。

  jdk1.8:arraylist像懶漢式,預設一開始建立一個長度為 0 的數組,當添加第一個元素時再建立一個始容量為10的數組。

  預設情況擴容都為原來數組的 1.5 倍。

  繼承關系:

JDK1.8源碼(六)——java.util.ArrayList類

  擴容原理:

JDK1.8源碼(六)——java.util.ArrayList類

  ①随機通路

  由于實作了 randomaccess 接口,它支援通過索引值去随機通路元素。

  ②增強foreach,底層還是使用的疊代器

  這種文法可以看成是 jdk 的一種文法糖,通過反編譯 class 檔案,可以看到生成的 java 檔案,還是通過調用 iterator 疊代器來周遊的。

  ③疊代器 iterator

  ④疊代器 listiterator

  源碼示例:

  繼承了abstractlist:abstractlist提供list接口的骨幹實作,以最大限度地減少"随機通路"資料存儲(如arraylist)實作llist所需的工作。

  實作了 list 接口:定義了實作該接口的類都必須要實作的一組方法,實作了所有可選清單操作。

  實作了 randmoaccess 接口:表明arraylist支援快速(通常是固定時間)随機通路。此接口的主要目的是允許一般的算法更改其行為,進而在将其應用到随機或連續通路清單時能提供良好的性能。比如在工具類 collections 中,應用二分查找方法時判斷是否實作了 randomaccess 接口:

  實作了 cloneable 接口:一個标記接口,接口内無任何方法體和常量的聲明。需要複寫object.clone()函數,表示它可以被克隆。

  實作了 serializable 接口:一個标記接口,辨別該類可序列化。

  源碼示例:讀一下源碼中的英文注釋。

  源碼示例:三個重載(重要)

  arraylist list = new arraylist(); // 集合長度初始化是0,而不是 10,jdk7才是10。

  arraylist list = new arraylist(7); // 指定大小時,初始多大就是多大。

  傳入一個集合。

  源碼示例:擴容原理

  源碼示例:真正擴容的方法

  說明:

  modcount給arraylist的疊代器使用的,在并發修改時,提供快速失敗行為,保證modcount在疊代期間不變,否則抛出concurrentmodificationexception異常。

  arraylist 的擴容,核心方法就是調用 arrays.copyof 方法,建立一個更大的數組,然後将原數組元素拷貝過去。

  總結:

  ①當通過 arraylist() 構造一個空集合,初始長度是為0的,第1次添加元素,會建立一個長度為10的數組,并将該元素指派到數組的第一個位置。

  ②第2次添加元素,集合不為空,由于集合大小size + 1 < 數組的長度 10,是以直接添加元素到數組的第二個位置,不用擴容。

  ③第 11 次添加元素,此時 size+1 = 11 > 數組長度10。這時候建立一個長度為10+10*0.5 = 15 的數組(擴容1.5倍),然後将原數組元素引用拷貝到新數組。并将第 11 次添加的元素指派到新數組下标為10的位置。

  ④第 integer.max_value - 8 = 2147483639,然後 2147483639%1.5=1431655759(這個數是要進行擴容)次添加元素,為了防止溢出,此時會直接建立一個 1431655759 + 1 大小的數組,這樣一直,每次添加一個元素,都隻擴大一個範圍。

  ⑤第 integer.max_value - 7 次添加元素時,建立一個大小為 integer.max_value 的數組,在進行元素添加。

  ⑥第 integer.max_value + 1 次添加元素時,抛出 outofmemoryerror 異常。

  源碼示例:将指定索引index處的元素修改。

  源碼示例:很簡單,略

  indexof(object o):傳回集合中第一次出現該元素的下标,沒有則傳回 -1。

  lastindexof(object o):傳回集合中最後一次出現該元素的下标。沒有則傳回 -1。

  傳回從 [fromindex, toindex) 的一個子串。但是注意,這裡隻是原集合的一個視圖。

  想要獨立出來一個集合,解決辦法如下:

  該方法用于回收多餘的記憶體。可以在确定集合不在添加多餘的元素之後,調用 trimtosize() 方法會将數組大小調整為集合元素的大小。

  注意:該方法會花時間來複制數組元素,是以應該在确定不會添加元素之後在調用。

JDK1.8源碼(六)——java.util.ArrayList類
JDK1.8源碼(六)——java.util.ArrayList類

疊代器

  注意:在進行 next() 方法調用的時候,會進行 checkforcomodification() 調用,該方法表示疊代器進行元素疊代時,如果同時進行增加和删除操作,會抛出 concurrentmodificationexception 異常。比如:

  注意:疊代器隻能向後周遊,不能向前周遊,能夠删除元素,但是不能新增元素。

  這是 list 集合特有的疊代器。可以一邊周遊,一邊新增或删除。

  相比于 iterator 疊代器, listiterator 多出了能向前疊代,以及新增元素的功能。

JDK1.8源碼(六)——java.util.ArrayList類
JDK1.8源碼(六)——java.util.ArrayList類

listiterator

  在arraylist類中,對上述接口的實作。

作者:craftsman-l