ArrayList源碼學習筆記(1)
標簽: jdk源碼
背景
之前關注了一個公眾號“彤哥讀源碼”,跟著一起學習了jdk里的很多類的源碼,包括集合類、線程類、并發類。真的是很好的公眾號,哈哈(因為確實是很好,這里愿意給路過的小伙伴安利一下,純自己主觀推薦,如果對公眾號作者有幫助,算是感謝這么好的文章對我的幫助了~)
其中,ArrayList是最簡單的一個了,但是讀完別人寫的東西其實還是不如自己實踐來的實在。所以自己再搞點東西。
文章鏈接(侵刪):https://mp.weixin.qq.com/s/a0zq-q8JuSwsLYX7tJ4VxA
計劃
準備按照一個路徑走,邊看文章,邊看源碼,然后自己手動做些調試。順便寫點文章,記錄一下學習和調試過程。
之后,自己手動實現一個ArrayList,可以根據情況進行多版本迭代。
正文
成員變量很簡單,文章中也有介紹。ArrayList的元素存儲在Object[] elementData數組中,size是當前保存了多少個元素。
還有兩個靜態final的空數組EMPTY_ELEMENTDATA和DEFAULTCAPACITY_EMPTY_ELEMENTDATA,看到這個就會產生疑惑,為什么會需要兩個靜態空數組呢?都是final的,反正不可變,用一個不就可以了?這其實跟構造函數有關系。
構造函數
ArrayList有三個構造方法,ArrayList()、ArrayList(int initialCapacity)、ArrayList(Collection c)。
ArrayList()會默認使用DEFAULTCAPACITY_EMPTY_ELEMENTDATA作為elementData的初始值;
ArrayList(int initialCapacity),如果initialCapacity > 0 就直接用這個值初始化數組長度了,等于0就直接用EMPTY_ELEMENTDATA。
ArrayList(Collection c) 如果c里沒有元素,默認也是用EMPTY_ELEMENTDATA。
(上面說的很啰嗦,看代碼一目了然)
增長邏輯
此時重點來了,如果用ArrayList()和ArrayList(0)實例化了兩個對象,它們在增加第一個變量的時候,elementData會怎么進行擴容?
這里的判斷告訴我們它是怎么做的。如果不手動指定初始容量,在第一次就會把容量設置為10。如果手動指定的初始容量是0,那么第一次就會把容量設置為你需要的那個值(調用add方法的時候,其實就是1)。
一開始我產生了額外的疑問:為什么代碼寫的這么啰嗦?minCapacity不就是1嗎,還能大于10?后來看了一下,確實能大于10,看一下addAll(Collection c)這個方法就明白了。如果一下子加入很多元素,也是會調用這個方法的。
那么這個邏輯我們怎么驗證一下呢?elementData是default的,自己寫代碼也沒權限獲取。這時候就是祭出“反射”大法的時候了,畢竟java里“萬物皆可反射”
import java.lang.reflect.Field;
import java.util.ArrayList;
public class ArrayListTest {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
// 通過使用ArrayList()和ArrayList(0)來進行對比
ArrayList<Integer> list = new ArrayList<>(0);
Field field = list.getClass().getDeclaredField("elementData");
field.setAccessible(true);
Object []ele = (Object[]) field.get(list);
System.out.println(ele.length);
Field field1 = list.getClass().getDeclaredField("DEFAULTCAPACITY_EMPTY_ELEMENTDATA");
field1.setAccessible(true);
Object []ele1 = (Object[]) field1.get(null);
// 這里能發現ele和ele1是同一個對象
System.out.println(ele);
System.out.println(ele1);
System.out.println(ele1 == ele);
// 逐漸增加元素,會發現容量每次增長一半
list.add(1);
list.add(1);
list.add(1);
list.add(1);
list.add(1);
System.out.println(list.size());
// 這里不能打印ele.length,想想為啥~(一開始就打錯了。。。)
// 即便一開始的容量是大于0的,比如20,當元素增長超過20的時候,也不能用ele了,因為復制產生了新數組
System.out.println(((Object[]) field.get(list)).length);
}
}
總結:
(1)如果不指定容量,新加入元素的時候容量最小是10;如果指定了容量為0,新加入元素的時候,容量是加入元素的個數;
(2)之后的容量增長都是每次增長一半。10->15->22->33 或者 0->1->2->3->4->6->9
(3)萬物皆可反射~
智能推薦
ArrayList學習筆記
概述: ArrayList是一個基于數組實現的列表集合類,父類是AbstractList和AbstractCollection,直接實現了List<E>,RandomAccess,Cloneable,java.io.Serializable接口,同時List<E>接口也繼承了Collection<E>接口,Collection<E>繼承了Iterab...
ArrayList的學習筆記
1、ArrayList的簡單介紹 ArrayList是一個動態數組隊列,它可自動擴容,每次擴容大小為原來的1.5倍,初始的默認值為10 ArrayList底層是由Object數組構成 ArrayList是線程不安全的,如果想使用線程安全的Arraylist可使用Collections.synchronizedList(List l)函數 ArrayList對刪除和添加(非兩端)操作是具有昂貴時間花...
jdk源碼閱讀筆記-ArrayList
2019獨角獸企業重金招聘Python工程師標準>>> 一、ArrayList概述 首先我們來說一下ArrayList是什么?它解決了什么問題?ArrayList其實是一個數組,但是有區別于一般的數組,它是一個可以動態改變大小的動態數組。ArrayList的關鍵特性也是這個動態的特性了,ArrayList的設計初衷就是為了解決Java數組長度不可變的問題。我們都知道在Java中數...
Java集合源碼(ArrayList)-筆記
ArrayList 初始化 無參:默認大小為空數組,10是第一次擴容的大小 指定大小 指定初始數據: jdk8一些小bug: 有初始數據初始化的時候,元素類型不是Object類型的會被轉成Object類型。 背景:ArrayList 初始化之后(ArrayList 元素非 Object 類型),再次調用 toArray 方法,得到 Object 數組,并且往 Object 數組賦值時,才會觸發此 ...
JDK源碼學習(四)---ArrayList
一、簡介 1、ArrayList繼承關系 2、繼承關系解析 1、頂層Iterable接口,可迭代 2、Collection繼承自Iterable,并添加了size()、isEmpty()、contains等方法。 3、List繼承了Collection接口,針對List的特性加入了get、set、sort、sublist等方法。 4、AbstractCollection中即有自己實現了方法體的一些...
猜你喜歡
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...