ArrayList原始碼分析–底層擴容機制
最近在復習Java基礎知識,故寫此博客記錄
先說結論:如果我們在初始集合時使用無參構造形式,那么ArrayList的初始大小為0,當我們第一次添加資料時,陣列大小為10,后續每次添加資料時(我們規定每次只添加一個資料,原因我們后面會說到)如果容量不夠,則集合擴容為原來的1.5倍數 Plus:此程式運行的環境為jdk15,不過8版本機制和這個大體上差不多
以下為演示程序
首先我們寫這樣一個簡單的程式:

我們開始除錯程式,
首先,我們先按 Ctrl+A進入查看AyyayList的空構造方法

看不懂沒關系,我們往上翻來找這個DEFAULTCAPACITY_EMPTY_ELEMENTDATA

從這里我們就可以發現,其實這段話的含義就是把ArrayList初始化為一個空陣列,讓然后我們跳出來繼續看,

此時集合的size(大小)為0,也印證了我們的想法
下面我們來看add方法
首先時對int資料型別的裝箱,變成integer型別,然后我們跳出來繼續看


這里的modCount記錄著我們的操作次數我們先不管它,方法里面又含有一個add方法,e就是我們要添加的元素,elementData是我們要操作的陣列,size是現在集合的大小,我們進入這個add方法
首先是檢驗陣列的容量是否足夠用于擴容,即檢驗下標是否等于陣列容量,如果為true,說明容量已經不足了,false則表示還有容量也就自然不需要執行擴容操作了,這里為true,我們執行擴容操作

這個時候我們才開始執行擴容操作grow方法

這里的minCapacity是現在集合最小需要的容量
oldCapacity:陣列現在的容量,

然后判斷集合大小是否大于0或者不為空,否,我們進入這個看起來很長的方法

這里操作其實很顯而易見,還記得我們之前的結論嗎?第一次擴容(這里我們討論的是無參構造的情況),擴容后的大小為10,
這里做的就是這一步操作,如果我們需要的容量(此時是1)小于10,那么我們就新創建一個大小為10的陣列,然后賦值給elementData也就是我們要操作的陣列,如果需要的容量大于10,比如為x(x>10),那么就創建一個大小為x的陣列,然后將它賦值給elementData,OK結束,
至此我們一直出堆疊,發現elementData的大小確實變成了10,將值e放入陣列集合的第一個位置,然后size+1,

至此我們的第一次擴容作業就結束啦,是不是覺得很簡單呢,
后續的9次回圈,就是正常添加資料,并不會觸發擴容操作,原因上面我們已經說過了,判斷陳述句是這句話,

好,接下來9次回圈我們就跳過,我們來看下一次容量不夠時程式執行的操作,
此時集合容量還是10,但我們即將插入第11個資料

前面一堆跟上面一樣的操作我就不再講了,直接開講不一樣的,
首先是程式檢測到集合已滿不足以添加新資料,即將執行grow方法

此時我們的集合已經大于0了,開始執行不一樣擴容的操作

我們首先進入ArraysSupport的newLength方法,這里有三個引數
oldLength,minGrowth,prefGrowth
oldLength時原來集合的大小,minGrowth是集合最小需要擴容的大小,值為:需要添加的資料數+集合的原來大小,prefGrowth是集合現在大小的一半,考慮到有些朋友可能不明白>>符號的意思,這里我找了一篇文章大家可以參考看一下Java中的>>,>>>
好啦我們繼續
又進入了一個方法

第一句話(關鍵點):int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
找出我們需要擴容的最大大小,這也就是為什么我們在開頭的結論中規定每次只添加一個資料,如果一次性添加的資料數x大于集合大小的一半y/2,那么我們擴容后的大小就不是原來的1.5倍(y/2+y)了 而是x+y,
第二句話是檢驗集合容量是否很大,這里我們不做討論,
本次的結果就是回傳一個值,該值為現在集合容量的1.5倍,
然后我們使用Arrays的copyOf方法來實作集合的擴容,這里我提一下為什么要用copyOf方法,因為這樣可以保證原來的資料還存在,如果創建一個新的物件的話,原來的資料就不存在了,后續就是一些賦值什么的操作啦,
以上就是我對于陣列集合的一些理解,本人學藝不精如果有講錯的地方請指正!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/335540.html
標籤:java
