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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android 获取ArrayList的Capacity

發(fā)布時間:2024/4/15 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android 获取ArrayList的Capacity 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.


今天,簡單講講如何獲取 

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ū)別。

  • /*** public方法,讓用戶能手動設(shè)置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) {//當(dāng)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);}//數(shù)組可被分配的最大容量;當(dāng)需要的數(shù)組尺寸超過VM的限制時,可能導(dǎo)致OutOfMemoryErrorprivate static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;/*** 增加數(shù)組的容量,確保它至少能容納指定的最小容量的元素量* @param minCapacity 期望的最小容量*/private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;//注意此處擴充capacity的方式是將其向右一位再加上原來的數(shù),實際上是擴充了1.5倍int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); //設(shè)置數(shù)組可被分配的最大容量// 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的容量不足以容納當(dāng)前的全部元素,設(shè)置 新的容量=“(原始容量x3)/2 + 1”public void ensureCapacity(int minCapacity) {modCount++; // 將“修改統(tǒng)計數(shù)”+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倍?

    這種算法構(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是私有的變量,一般是無法獲取到的,不過可以通過反射獲取。具體代碼很簡單:


    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就講完了。


    就這么簡單。

    總結(jié)

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

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。