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