JDK1.8中ArrayList是如何擴(kuò)容的
ArrayList簡介:
ArrayList實(shí)現(xiàn)了List接口它是一個(gè)可調(diào)整大小的數(shù)組可以用來存放各種形式的數(shù)據(jù)。并提供了包括CRUD在內(nèi)的多種方法可以對(duì)數(shù)據(jù)進(jìn)行操作但是它不是線程安全的,外ArrayList按照插入的順序來存放數(shù)據(jù)。
在講擴(kuò)容機(jī)制之前,我們需要了解一下ArrayList中最主要的幾個(gè)變量:
private static final int DEFAULT_CAPACITY = 10;//數(shù)組默認(rèn)初始容量 private static final Object[] EMPTY_ELEMENTDATA = {};//定義一個(gè)空的數(shù)組實(shí)例以供其他需要用到空數(shù)組的地方調(diào)用 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//定義一個(gè)空數(shù)組,跟前面的區(qū)別就是這個(gè)空數(shù)組是用來判斷ArrayList第一添加數(shù)據(jù)的時(shí)候要擴(kuò)容多少。默認(rèn)的構(gòu)造器情況下返回這個(gè)空數(shù)組 transient Object[] elementData;//數(shù)據(jù)存的地方它的容量就是這個(gè)數(shù)組的長度,同時(shí)只要是使用默認(rèn)構(gòu)造器(DEFAULTCAPACITY_EMPTY_ELEMENTDATA )第一次添加數(shù)據(jù)的時(shí)候容量擴(kuò)容為DEFAULT_CAPACITY = 10 private int size;//當(dāng)前數(shù)組的長度
本題的所有的講解都是基于JDK8
這道題考察了ArrayList的構(gòu)造器和對(duì)擴(kuò)容機(jī)制的了解,本篇博客基于此出發(fā)講解ArrayList的擴(kuò)容機(jī)制
想要做出這道題必須了解ArrayList的構(gòu)造函數(shù),ArrayList的構(gòu)造函數(shù)總共有三個(gè):
ArrayList()
構(gòu)造一個(gè)空的數(shù)組。JDK7中構(gòu)造一個(gè)初始容量為10的空列表但是JDK8中只是構(gòu)造一個(gè)空的數(shù)組ArrayList(Collection<? extends E> c)
構(gòu)造一個(gè)包含指定 collection 的元素的數(shù)組,這些元素是按照該 collection 的迭代器返回它們的順序排列的。ArrayList(int initialCapacity)
構(gòu)造一個(gè)具有指定初始容量的空數(shù)組。
我們重點(diǎn)來看這兩個(gè)ArrayList(int initialCapacity)
,ArrayList()
構(gòu)造函數(shù)
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
初始化一個(gè)空數(shù)組,這是JDK8不同于之前版本的地方
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); } }
對(duì)于形參initialCapacity
判斷,如果大于0那么就聲明一個(gè)和形參一樣大小的數(shù)組。了解到這里似乎這道題的正確答案也出來了即選擇A,并沒有發(fā)生擴(kuò)容
但是作為一名合格的程序員要有探索精神,題目提到了擴(kuò)容,既然ArrayList底層是一個(gè)數(shù)組,那么就肯定會(huì)滿,什么時(shí)候發(fā)生擴(kuò)容呢?
//1.add方法為添加元素在數(shù)組末尾 public boolean add(E e) { //確保數(shù)組容量 size指向數(shù)組的末尾 ensureCapacityInternal(size + 1); //在完成添加之前要確保數(shù)組長度足夠 elementData[size++] = e; return true; } //3.elementData為ArrayList底層維護(hù)的數(shù)組,minCapacity為此時(shí)數(shù)組的大小 private static int calculateCapacity(Object[] elementData, int minCapacity) { //如果數(shù)組為初始化的值,就初始化數(shù)組容量為10(空參的構(gòu)造方法下首次添加) if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } //2.minCapacity表示此時(shí)數(shù)組的大小 private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } //4.minCapacity表示此時(shí)數(shù)組的大小 private void ensureExplicitCapacity(int minCapacity) { modCount++; //如果此時(shí)數(shù)組容量的大小不夠就擴(kuò)容 if (minCapacity - elementData.length > 0) grow(minCapacity); }
源碼讀到這里,我們明白了,當(dāng)我們每次向ArrayList添加元素的時(shí)候,都會(huì)首先確保數(shù)組容量夠放下元素如果不夠就會(huì) grow(minCapacity)
調(diào)用擴(kuò)容函數(shù),那么秉承著探索的精神,原本大小的數(shù)組擴(kuò)容之后變成多大了呢?還得繼續(xù)看源碼
//擴(kuò)容源碼 private void grow(int minCapacity) { //獲取當(dāng)前數(shù)組的長度 int oldCapacity = elementData.length; //>>右移相當(dāng)于整除2,新容量相當(dāng)于就舊容量的1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); //如果擴(kuò)容后的容量還不夠那么就以需要的容量為新容量 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //如果新容量已經(jīng)超過最大容量了,那么就直接使用最大容量 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); //講新容量的數(shù)組拷貝 elementData = Arrays.copyOf(elementData, newCapacity); }
源碼大致讀完后,我們明白了ArrayList的自動(dòng)擴(kuò)容機(jī)制,每次新添加元素的時(shí)候都會(huì)判斷是否能夠容下,如果不夠就會(huì)發(fā)生擴(kuò)容,擴(kuò)容的大小為原大小的1.5倍數(shù),明白這些以后讓我們看看下面這段程序擴(kuò)容了幾次呢??容量是多少呢?
ArrayList<Integer> arrayList = new ArrayList<Integer>(20); for(int i=1;i<=50;i++) { arrayList.add(i); }
前20次添加不會(huì)發(fā)生擴(kuò)容,當(dāng)21元素添加時(shí)數(shù)組容量從20擴(kuò)容到30,當(dāng)添加31元素時(shí)數(shù)組容量從30擴(kuò)容到45,當(dāng)添加46元素時(shí)數(shù)組容量從45擴(kuò)容到67
到此這篇關(guān)于JDK1.8中ArrayList是如何擴(kuò)容的的文章就介紹到這了,更多相關(guān)JDK1.8 ArrayList擴(kuò)容內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot項(xiàng)目之相互依賴報(bào)錯(cuò)問題(基于idea)
這篇文章主要介紹了springboot項(xiàng)目之相互依賴報(bào)錯(cuò)問題(基于idea),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02feign post參數(shù)對(duì)象不加@RequestBody的使用說明
這篇文章主要介紹了feign post參數(shù)對(duì)象不加@RequestBody的使用說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10Python實(shí)現(xiàn)filter函數(shù)實(shí)現(xiàn)字符串切分
這篇文章主要介紹了Python實(shí)現(xiàn)filter函數(shù)實(shí)現(xiàn)字符串切分,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03SpringBoot 下集成緩存工具類 CacheManager
這篇文章主要介紹了Springboot下集成緩存工具類CacheManager,想進(jìn)一步了解相關(guān)知識(shí)的同學(xué),可以詳細(xì)閱讀本文2023-03-03Java volatile的適用場(chǎng)景實(shí)例詳解
在本文里我們給大家整理了一篇關(guān)于Java volatile的適用場(chǎng)景實(shí)例內(nèi)容和知識(shí)點(diǎn),需要的朋友們可以學(xué)習(xí)下。2019-08-08SpringBoot整合JDBC的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot整合JDBC的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01JVM?jstack實(shí)戰(zhàn)之死鎖問題詳解
如果在生產(chǎn)環(huán)境發(fā)生了死鎖,我們將看到的是部署的程序沒有任何反應(yīng)了,這個(gè)時(shí)候我們可以借助?jstack進(jìn)行分析,下面我們實(shí)戰(zhàn)操作查找死鎖的原因2022-10-10