<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
對於 ArrayList 的動態擴容機制想必大家都聽說過,之前的文章中也談到過,不過由於時間久遠,早已忘卻。
所以利用這篇文章做做筆記,加深理解記憶
要了解其動態擴容機制就必須先看它的原始碼,原始碼是基於 jdk 1.8 的
// 如果不指定容量(空構造器),則在新增資料時的空構造器預設初始容量最小為 10 private static final int DEFAULT_CAPACITY = 10; // 出現在需要用到空陣列的地方,其中一處是使用自定義初始容量構造方法時候如果你指定初始容量為0的時候,那麼elementData指向該陣列 // 另一處是使用包含指定collection集合元素的列表的構造方法時,如果被包含的列表中沒有資料,那麼elementData指向該陣列 private static final Object[] EMPTY_ELEMENTDATA = {}; // 如果使用預設構造方法,那麼elementData指向該陣列 // 在新增元素時會判斷是否是使用預設構造器第一次新增,如果是陣列就會擴容至10個容量 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; // 預設未初始化的儲存 ArrayList集合元素的底層陣列,其長度就是 ArrayList的容量 transient Object[] elementData; // 私有的elementData陣列中具體的元素物件的數量,可通過size方法獲得。預設初始值為0,在add、remove等方法時size會改變 private int size;
可以看到 ArrayList 底層核心是一個 Object[] elementData 的陣列
// 預設的構造器 public ArrayList() { // Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {} 空陣列 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } // 自定義容量大小的構造器 public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
從上面的構造器中,可以得出以下結論
根據上面的兩個結論,不管是使用預設或有參構造器時,我們可以使其初始容量為 0,那麼它的動態擴容發生在哪裡?
可以肯定就發生在 add() 方法中,那麼檢視 add() 方法原始碼如下
public boolean add(E e) { // ensureCapacityInternal() 如下 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
按照我們第一次 add, size 肯定是 0 了,所以 ensureCapacityInternal 這個函數傳入的是 1
// 第一次 add 時,引數 minCapacity = 1 private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } // calculateCapacity() 方法 private static int calculateCapacity(Object[] elementData, int minCapacity) { // 如果是第一次 add 元素 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // minCapacity 設定為 DEFAULT_CAPACITY 與 minCapacity 的最大值 return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } // ensureExplicitCapacity() 方法 private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }
elementData.length 是陣列長度,它是隨著陣列擴容而動態變化的
首先看 calculateCapacity() 方法
再看 ensureExplicitCapacity() 方法
private void grow(int minCapacity) { // 原容量 int oldCapacity = elementData.length; // 擴容後的容量,擴大到原容量的 1.5 倍左右,右移一位相當於原數值除以 2 的商 int newCapacity = oldCapacity + (oldCapacity >> 1); // 如果新容量減去最小容量的值小於 0 if (newCapacity - minCapacity < 0) // 新容量等於最小容量 newCapacity = minCapacity; // 如果新容量減去建議最大容量的值大於 0 if (newCapacity - MAX_ARRAY_SIZE > 0) // 調整新容量上限或者丟擲 OutOfMemoryError newCapacity = hugeCapacity(minCapacity); // 最終進行新陣列的構建和重新賦值,此後原陣列被摒棄 // elementData:原陣列; newCapacity:新陣列容量 elementData = Arrays.copyOf(elementData, newCapacity); }
elementData.length 是陣列長度,它是隨著陣列拷貝而動態變化的
如果是第一次 add 元素,由上面的方法可知引數 minCapacity = 10,第一次 add 元素 oldCapacity = 0,可得知 newCapacity = 0 + 0,由於 newCapacity - minCapacity < 0,所以 newCapacity = minCapacity = 10 重新賦值,最終進行新陣列的構建和拷貝賦值
如果使用 ArrayList 的預設無參構造器時,它的初始容量就是 0
如果使用 ArrayList 的有參構造器時,它的初始容量就是你傳入的引數 initialCapacity的值
ArrayList 的初始容量為 0,當第一次 add 元素時,才會發生擴容操作,它的擴容大小是 10
當第一次 add 元素完成後,此時的 elementData.length = 10,後面要想發生擴容操作,必須 minCapacity - elementData.length > 0 為 true,即 minCapacity 最小為 11,也就是說當 ArrayList 第十一次 add 時,才會接著發生擴容操作,且擴容大小為 15 = 10 + 5
public class TestArrayList { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); list.add(6); list.add(7); list.add(8); list.add(9); list.add(10); list.add(11);// 打上斷點 } }
add() 方法打上斷點
ensureCapacityInternal() 方法打上斷點
ensureExplicitCapacity() 方法打上斷點
grow() 方法打上斷點
以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45