android 获取ArrayList的Capacity
今天,簡單講講如何獲取
ArrayList的Capacity。
這里,需要了解一下ArrayList的源碼。
一.ArrayList的源碼解析
每個ArrayList實例都有一個容量,該容量是指用來存儲列表元素的數(shù)組的大小。它總是至少等于列表的大小。隨著向ArrayList中不斷添加元素,其容量也自動增長。自動增長會帶來數(shù)據(jù)向新數(shù)組的重新拷貝,因此,如果可預(yù)知數(shù)據(jù)量的多少,可在構(gòu)造ArrayList時指定其容量。在添加大量元素前,應(yīng)用程序也可以使用ensureCapacity操作來增加ArrayList實例的容量,這可以減少遞增式再分配的數(shù)量。
這里所說的容量(Capacity)? 不是我們通過ArrayList.getSize()獲取的返回值,而是ArrayList里的數(shù)組的大小,即ArrayList開辟的內(nèi)存的大小。
有文章說ArrayList默認(rèn)構(gòu)造的容量為10,沒錯。 因為ArrayList的底層是由一個Object[]數(shù)組構(gòu)成的,而這個Object[]數(shù)組,默認(rèn)的長度是10,所以有的文章會說ArrayList長度容量為10。
然而你所指的size()方法,指的是“邏輯”長度。
所謂“邏輯”長度,是指內(nèi)存已存在的“實際元素的長度” 而“空元素不被計算”
即:當(dāng)你利用add()方法,向ArrayList內(nèi)添加一個“元素”時,邏輯長度就增加1位。 而剩下的9個空元素不被計算。
ArrayList<String> list = new ArrayList<String>(); System.out.println("size = " + list.size());
輸出結(jié)果如下:
size = 0
ArrayList默認(rèn)size()是0.而這時的Capacity已經(jīng)是10.
ArrayList源碼解析
JDK版本不一樣,ArrayList類的源碼也不一樣。
- JDK1.8
ArrayList類結(jié)構(gòu)
//通過ArrayList實現(xiàn)的接口可知,其支持隨機訪問,能被克隆,支持序列化 public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable {//序列版本號private static final long serialVersionUID = 8683452581122892189L;//默認(rèn)初始容量private static final int DEFAULT_CAPACITY = 10;//被用于空實例的共享空數(shù)組實例private static final Object[] EMPTY_ELEMENTDATA = {};//被用于默認(rèn)大小的空實例的共享數(shù)組實例。其與EMPTY_ELEMENTDATA的區(qū)別是:當(dāng)我們向數(shù)組中添加第一個元素時,知道數(shù)組該擴充多少。private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};/*** Object[]類型的數(shù)組,保存了添加到ArrayList中的元素。ArrayList的容量是該Object[]類型數(shù)組的長度* 當(dāng)?shù)谝粋€元素被添加時,任何空ArrayList中的elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA將會被* 擴充到DEFAULT_CAPACITY(默認(rèn)容量)。*/transient Object[] elementData; //非private是為了方便嵌套類的訪問// ArrayList的大小(指其所含的元素個數(shù))private int size;...... }
ArrayList包含了兩個重要的對象:elementData 和 size。
elementData 是”O(jiān)bject[] 類型的數(shù)組”,它保存了添加到ArrayList中的元素。實際上,elementData是個動態(tài)數(shù)組,我們能通過構(gòu)造函數(shù) ArrayList(int initialCapacity)來執(zhí)行它的初始容量為initialCapacity;如果通過不含參數(shù)的構(gòu)造函數(shù)ArrayList()來創(chuàng)建 ArrayList,則elementData的容量默認(rèn)是10。elementData數(shù)組的大小會根據(jù)ArrayList容量的增長而動態(tài)的增長,具 體的增長方式,請參考源碼分析中的ensureCapacity()函數(shù)。
size 則是動態(tài)數(shù)組的實際大小。
構(gòu)造函數(shù)
ArrayList提供了三種方式的構(gòu)造器,可以構(gòu)造一個默認(rèn)初始容量為10的空列表、構(gòu)造一個指定初始容量的空列表以及構(gòu)造一個包含指定collection的元素的列表,這些元素按照該collection的迭代器返回的順序排列的。
/*** 構(gòu)造一個指定初始容量的空列表* @param initialCapacity ArrayList的初始容量* @throws IllegalArgumentException 如果給定的初始容量為負值*/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);}}// 構(gòu)造一個默認(rèn)初始容量為10的空列表public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}/*** 構(gòu)造一個包含指定collection的元素的列表,這些元素按照該collection的迭代器返回的順序排列的* @param c 包含用于去構(gòu)造ArrayList的元素的collection* @throws NullPointerException 如果指定的collection為空*/public ArrayList(Collection<? extends E> c) {elementData = c.toArray();if ((size = elementData.length) != 0) {// c.toArray()可能不會正確地返回一個 Object[]數(shù)組,那么使用Arrays.copyOf()方法if (elementData.getClass() != Object[].class)//Arrays.copyOf()返回一個 Object[].class類型的,大小為size,元素為elementData[0,...,size-1]elementData = Arrays.copyOf(elementData, size, Object[].class);} else {// replace with empty array.this.elementData = EMPTY_ELEMENTDATA;}}
ArrayList構(gòu)造一個默認(rèn)初始容量為10的空列表:
初始情況:elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; size = 0;
當(dāng)向數(shù)組中添加第一個元素時,通過add(E e)方法中調(diào)用的ensureCapacityInternal(size + 1)方法,即ensureCapacityInternal(1);
在ensureCapacityInternal(int minCapacity)方法中,可得的minCapacity=DEFAULT_CAPACITY=10,然后再調(diào)用ensureExplicitCapacity(minCapacity)方法,即ensureExplicitCapacity(10);
在ensureExplicitCapacity(minCapacity)方法中調(diào)用grow(minCapacity)方法,即grow(10),此處為真正具體的數(shù)組擴容的算法,在此方法中,通過elementData = Arrays.copyOf(elementData, 10)具體實現(xiàn)了elementData數(shù)組初始容量為10的構(gòu)造。
調(diào)整數(shù)組的容量
從add()與addAll()方法中可以看出,每當(dāng)向數(shù)組中添加元素時,都要去檢查添加元素后的個數(shù)是否會超出當(dāng)前數(shù)組的長度,如果超出,數(shù)組將會進行擴容,以滿足添加數(shù)據(jù)的需求。數(shù)組擴容實質(zhì)上是通過私有的方法ensureCapacityInternal(int minCapacity) -> ensureExplicitCapacity(int minCapacity) -> grow(int minCapacity)來實現(xiàn)的,但在jdk1.8中,向用戶提供了一個public的方法ensureCapacity(int minCapacity)使用戶可以手動的設(shè)置ArrayList實例的容量,以減少遞增式再分配的數(shù)量。此處與jdk1.6中直接通過一個公開的方法ensureCapacity(int minCapacity)來實現(xiàn)數(shù)組容量的調(diào)整有區(qū)別。
附:jdk1.6中ensureCapacity(int minCapacity)方法:
為什么ArrayList自動容量擴充選擇擴充1.5倍?
這種算法構(gòu)造出來的新的數(shù)組長度的增量都會比上一次大( 而且是越來越大) ,即認(rèn)為客戶需要增加的數(shù)據(jù)很多,而避免頻繁newInstance 的情況。
這里,總結(jié)一下,ArrayList初始化的Capacity是10,當(dāng)ArrayList的添加的元素大于Capacity時,ArrayList自動擴充1.5倍的Capacity。這個自動容量擴充會新建一個數(shù)組,然后把之前的數(shù)據(jù)考到新的數(shù)組里,然后添加新的數(shù)據(jù),所以是比較耗時的操作。如果知道ArrayList的最大容量,最好在才初始化時進行指定,可以避免這個問題
二,獲取ArrayList的Capacity
因為Capacity是私有的變量,一般是無法獲取到的,不過可以通過反射獲取。具體代碼很簡單:
這樣基本就可以獲取到ArrayList的Capacity。
android 獲取ArrayList的Capacity就講完了。
就這么簡單。
總結(jié)
以上是生活随笔為你收集整理的android 获取ArrayList的Capacity的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android error: undef
- 下一篇: android jni jbyteArr