Java ArrayList擴容實現(xiàn)原理

一、.ArrayList:

寫過的項目到現(xiàn)在基本上面向業(yè)務(wù)域查詢返回大列表都是使用ArrayList來存儲業(yè)務(wù)數(shù)據(jù)的。

定義:ArrayList是List接口的可變數(shù)組的實現(xiàn)。實現(xiàn)了所有的可選列表的操作并允許包括null在內(nèi)的所有元素。除了實現(xiàn)List接口外,此類還提供一些方法來操作內(nèi)部用來存儲列表的數(shù)組的大小。

每個ArrayList實例都有一個容量,該容量是指來存儲列表元素的數(shù)組的大小,該容量至少等于列表數(shù)組的大小,隨著ArrayList的不斷添加元素,其容量也在自動增長,自動增長會將原來數(shù)組的元素向新的數(shù)組進行copy。因此,如果根據(jù)業(yè)務(wù)場景來提前預(yù)判數(shù)據(jù)量的大小。可在構(gòu)造ArrayList時指定其容量。在添加大量元素前,應(yīng)用程序可以使用ensureCapacity操作來增加ArrayList實例的容量,這樣就可以減少遞增式再分配數(shù)量的操作。

注意:我們都知道ArrayList不是線程安全的,如果存在多線程訪問ArrayList實例的場景,其中一個線程要在改變ArrayList列表結(jié)構(gòu)之前,需要先對它這個操作保持線程同步。

ArrayList繼承了AbstractList抽象類并實現(xiàn)了List接口,底層使用數(shù)組保存所有元素。


AbstractList主要作用是定義抽象對數(shù)組操作的公共主要行為,供具備相似功能的子類來具體實現(xiàn)自己特定的邏輯。

二、初始化

public ArrayList();默認(rèn)的構(gòu)造器,將會以默認(rèn)的大小來初始化內(nèi)部的數(shù)組

public ArrayList(int initialCapacity);用指定的大小來初始化內(nèi)部的數(shù)組

public ArrayList(Collectio<? extends E> c);用一個ICollection對象來構(gòu)造,并將該集合的元素添加到ArrayList


public ArrayList();默認(rèn)的構(gòu)造器

/**

* Shared empty array instance used for empty instances.

*/

private static final Object[] EMPTY_ELEMENTDATA = {};

/**

* Constructs an empty list with an initial capacity of ten.

*/

public ArrayList() {

super();

this.elementData = EMPTY_ELEMENTDATA;

}

我本地JDK1.7 默認(rèn)數(shù)組長度是0,JDK1.6初始化大小是10

(1)添加元素,確定內(nèi)部容量

/**

* Default initial capacity.

*/

private static final int DEFAULT_CAPACITY = 10;

/** * Appends the specified element to the end of this list. * * @param e element to be appended to this list * @returntrue(as specified by {@link Collection#add}) */?

?public boolean add(E e) {?

?ensureCapacityInternal(size + 1); //確保內(nèi)部容量,判斷當(dāng)前容量大小,如果不夠就通過擴容來確保容量;size大小表示執(zhí)行添加元素之前的元素個數(shù),并不是ArrayList的容量,容量是elementData數(shù)組長度

?// Increments modCount!!?

?elementData[size++] = e;?

?return true;

?}

下面關(guān)注下ensureCapacityInternal(size + 1)是如何擴容的。

private void ensureCapacityInternal(int minCapacity) {

//如果實際存儲數(shù)組是空數(shù)組,則最小的容量是默認(rèn)容量,JDK1.7是10

if (elementData == EMPTY_ELEMENTDATA) {

minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);

}

ensureExplicitCapacity(minCapacity);

}

private void ensureExplicitCapacity(int minCapacity) {

modCount++;

// overflow-conscious code

//如果數(shù)組長度elementData.length小于最小容量就需要擴容

if (minCapacity - elementData.length > 0)

grow(minCapacity);

}

以上,elementData是用來存儲實際數(shù)據(jù)的數(shù)組,minCapacity是最小的擴容容量。

三.擴容(重點)

/**

* 增加容量,以確保它至少能容納由最小容量參數(shù)指定的元素數(shù)

* @param minCapacity 所需要的最小容量

*/

private void grow(int minCapacity) {

// overflow-conscious code

int oldCapacity = elementData.length;

//?int newCapacity = oldCapacity + oldCapacity * 0.5 也就是擴容了1.5倍

int newCapacity = oldCapacity + (oldCapacity >> 1);

if (newCapacity - minCapacity < 0)

newCapacity = minCapacity;

//?MAX_ARRAY_SIZE:private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

// 這個最大值用來分配給數(shù)組的,由于不同的JVM需要在數(shù)組中需要存放些頭部信息,如果分配過大可能會導(dǎo)致內(nèi)存溢出:提示請求的數(shù)組大小超過了JVM限制

if (newCapacity - MAX_ARRAY_SIZE > 0)

newCapacity = hugeCapacity(minCapacity);

// minCapacity is usually close to size, so this is a win:

// 將獲取到的擴容的容量復(fù)制當(dāng)前到當(dāng)前數(shù)組

elementData = Arrays.copyOf(elementData, newCapacity);

}

private static int hugeCapacity(int minCapacity) {

if (minCapacity < 0) // overflow

throw new OutOfMemoryError();

return (minCapacity > MAX_ARRAY_SIZE) ?

Integer.MAX_VALUE :

MAX_ARRAY_SIZE;

}

總結(jié):ArrayList是采取延遲分配對象數(shù)組大小空間的,當(dāng)?shù)谝淮翁砑釉貢r才會分配10個對象空間,當(dāng)添加第11個元素的時候,會擴容1.5倍,當(dāng)添加到16個元素的時候擴容為15*1.5=22,以此類推。

ArrayList每次擴容都是通過Arrays.copyof(elementData, newCapacity)來實現(xiàn)的。

當(dāng)我們在明確對象的大致數(shù)目時候提前指定初始化數(shù)組的大小是一個非常明智的選擇。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 文章有點長,比較啰嗦,請耐心看完?。ɑ贏ndroid API 25) 一、概述 首先得明白ArrayList在數(shù)...
    JerryloveEmily閱讀 3,385評論 2 15
  • 【默默耕耘】20161206 day 13 Tuesday 1.畫日記:聽了一遍第三節(jié)課?;丶?洗手時就和兒子商量...
    ysmalina閱讀 206評論 0 0
  • 明天要出趟遠(yuǎn)門,心里亂糟糟的,我不是個特別膽兒大的人,也不常一個人睡,所以啊,真是有些憂心。還要去學(xué)校辦事,...
    小鎮(zhèn)Y胖Y閱讀 214評論 0 0
  • 粽子節(jié)后…… 回首和妳…… 我……和……我來時的路…… 都已成了風(fēng)景…… TMD…… 有個人…… 住在心底…… 卻...
    曄0114閱讀 137評論 0 2
  • 總有一天會無可自拔的愛上自己啊,雖然目前對于各方面還是諸多挑剔。最近做夢老夢見以前都不曾過多關(guān)注的老同學(xué),一群群的...
    阿琳家的阿佳和阿飛閱讀 176評論 0 1

友情鏈接更多精彩內(nèi)容