日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android 获取ArrayList的Capacity

發布時間:2024/4/15 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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)來實現數組容量的調整有區別。

  • /*** public方法,讓用戶能手動設置ArrayList的容量* @param minCapacity 期望的最小容量*/public void ensureCapacity(int minCapacity) {int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)// any size if not default element table? 0// larger than default for default empty table. It's already// supposed to be at default size.: DEFAULT_CAPACITY;if (minCapacity > minExpand) {ensureExplicitCapacity(minCapacity);}}private void ensureCapacityInternal(int minCapacity) {//當elementData為空時,ArrayList的初始容量最小為DEFAULT_CAPACITY(10)if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}ensureExplicitCapacity(minCapacity);}private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);}//數組可被分配的最大容量;當需要的數組尺寸超過VM的限制時,可能導致OutOfMemoryErrorprivate static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;/*** 增加數組的容量,確保它至少能容納指定的最小容量的元素量* @param minCapacity 期望的最小容量*/private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;//注意此處擴充capacity的方式是將其向右一位再加上原來的數,實際上是擴充了1.5倍int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); //設置數組可被分配的最大容量// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);}private static int hugeCapacity(int minCapacity) {if (minCapacity < 0) // overflowthrow new OutOfMemoryError();return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;}


    附:jdk1.6中ensureCapacity(int minCapacity)方法:

    // 確定ArrarList的容量。 // 若ArrayList的容量不足以容納當前的全部元素,設置 新的容量=“(原始容量x3)/2 + 1”public void ensureCapacity(int minCapacity) {modCount++; // 將“修改統計數”+1int oldCapacity = elementData.length;if (minCapacity > oldCapacity) {Object oldData[] = elementData;int newCapacity = (oldCapacity * 3)/2 + 1;if (newCapacity < minCapacity)newCapacity = minCapacity;elementData = Arrays.copyOf(elementData, newCapacity);}}


    為什么ArrayList自動容量擴充選擇擴充1.5倍?

    這種算法構造出來的新的數組長度的增量都會比上一次大( 而且是越來越大) ,即認為客戶需要增加的數據很多,而避免頻繁newInstance 的情況。


    這里,總結一下,ArrayList初始化的Capacity是10,當ArrayList的添加的元素大于Capacity時,ArrayList自動擴充1.5倍的Capacity。這個自動容量擴充會新建一個數組,然后把之前的數據考到新的數組里,然后添加新的數據,所以是比較耗時的操作。如果知道ArrayList的最大容量,最好在才初始化時進行指定,可以避免這個問題



    二,獲取ArrayList的Capacity


    因為Capacity是私有的變量,一般是無法獲取到的,不過可以通過反射獲取。具體代碼很簡單:


    import java.lang.reflect.*; import java.util.*;public class Test{public static void main(String[] args) throws Exception {ArrayList list = new ArrayList();Field f = ArrayList.class.getDeclaredField("elementData");f.setAccessible(true);Object[] elementData = (Object[])f.get(list);System.out.println(elementData.length);} }

    這樣基本就可以獲取到ArrayList的Capacity。


    android 獲取ArrayList的Capacity就講完了。


    就這么簡單。

    總結

    以上是生活随笔為你收集整理的android 获取ArrayList的Capacity的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。