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