博客專欄

EEPW首頁(yè) > 博客 > 扣丁學(xué)堂Java培訓(xùn)之容器類ArrayList源碼分析

扣丁學(xué)堂Java培訓(xùn)之容器類ArrayList源碼分析

發(fā)布人:扣丁客1 時(shí)間:2020-12-28 來(lái)源:工程師 發(fā)布文章

本文是針對(duì)Java1.8的源代碼進(jìn)行解析的,可能會(huì)和其他版本有所出入。

一、繼承和實(shí)現(xiàn)

繼承:AbstractList

實(shí)現(xiàn):List,RandomAccess,Cloneable,Serializable接口

publicclassArrayListextendsAbstractList
implementsList,RandomAccess,Cloneable,java.io.Serializable{
}


二、全局變量

1.默認(rèn)容量

privatestaticfinalintDEFAULT_CAPACITY=10;

2.空的對(duì)象數(shù)組

privatestaticfinalObject[]EMPTY_ELEMENTDATA={};

3.默認(rèn)的空數(shù)組

//無(wú)參構(gòu)造函數(shù)創(chuàng)建的數(shù)組

privatestaticfinalObject[]DEFAULTCAPACITY_EMPTY_ELEMENTDATA={};

4.存放數(shù)據(jù)的數(shù)組的緩存變量,不可序列化

transientObject[]elementData;

5.數(shù)組的大小

privateintsize;

三、構(gòu)造方法

1.帶有容量initialCapacity的構(gòu)造方法

源碼解釋:

publicArrayList(intinitialCapacity){

//如果初始化時(shí)ArrayList大小大于0

if(initialCapacity>0){

//new一個(gè)該大小的object數(shù)組賦給elementData

this.elementData=newObject[initialCapacity];

}elseif(initialCapacity==0){//如果大小為0

//將空數(shù)組賦給elementData

this.elementData=EMPTY_ELEMENTDATA;

}else{//小于0

//則拋出IllegalArgumentException異常

thrownewIllegalArgumentException("IllegalCapacity:"+

initialCapacity);

}

}

2.不帶參數(shù)的構(gòu)造方法

源碼解釋:

publicArrayList(){

//直接將空數(shù)組賦給elementData

this.elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

}

3.帶參數(shù)Collection的構(gòu)造方法

源碼解釋:

參數(shù)c為一個(gè)Collection,Collection的實(shí)現(xiàn)類大概有以下幾種常用類型:

List:元素可以重復(fù)的容器

Set:元素不可重復(fù)的容器

Queue:結(jié)構(gòu)是一個(gè)隊(duì)列,先進(jìn)先出

這個(gè)構(gòu)造方法的意思是,將一個(gè)Collection實(shí)現(xiàn)類的對(duì)象轉(zhuǎn)換為一個(gè)ArrayList,但是c容器裝的內(nèi)容

必須為ArrayList裝的內(nèi)容的子類。例如,將一個(gè)裝了String內(nèi)容的HashSet轉(zhuǎn)換為裝了String內(nèi)容的

ArrayList,使得ArrayList的大小和值數(shù)組都是HashSet的大小和值數(shù)組。具體實(shí)現(xiàn)如下代碼,首先調(diào)

用c(Collection的具體實(shí)現(xiàn)類)的toArray方法,具體大家可以看各個(gè)實(shí)現(xiàn)類的toArray方法,但是大

概意思都是將c容器轉(zhuǎn)換為object類型的數(shù)組,因?yàn)樗鼈兊姆祷刂刀际莖bject[]。之于下面的兩個(gè)判斷

是當(dāng)?shù)玫降膃lementData的類名不是Object類名的時(shí)候或者是長(zhǎng)度為0的時(shí)候才會(huì)執(zhí)行。

publicArrayList(Collectionc){

elementData=c.toArray();

if((size=elementData.length)!=0){

if(elementData.getClass()!=Object[].class)

elementData=Arrays.copyOf(elementData,size,Object[].class);

}else{

//replacewithemptyarray.

this.elementData=EMPTY_ELEMENTDATA;

}

}

四、方法

1.trimToSize()

說(shuō)明:將ArrayList的容量設(shè)置為當(dāng)前size的大小。首先需要明確一個(gè)概念,ArrayList的size就是ArrayList的元素個(gè)數(shù),length是ArrayList申請(qǐng)的內(nèi)容空間長(zhǎng)度。ArrayList每次都會(huì)預(yù)申請(qǐng)多一點(diǎn)空間,以便添加元素的時(shí)候不需要每次都進(jìn)行擴(kuò)容操作,例如我們的元素個(gè)數(shù)是10個(gè),它申請(qǐng)的內(nèi)存空間必定會(huì)大于10,即length>size,而這個(gè)方法就是把ArrayList的內(nèi)存空間設(shè)置為size,去除沒(méi)有用到的null值空間。這也就是我們?yōu)槭裁疵看卧讷@取數(shù)據(jù)長(zhǎng)度是都是調(diào)用list.size()而不是list.length()。

源碼解釋:首先modCount是從類java.util.AbstractList繼承的字段,這個(gè)字段主要是為了防止在多線程操作的情況下,List發(fā)生結(jié)構(gòu)性的變化,什么意思呢?就是防止一個(gè)線程正在迭代,另外一個(gè)線程進(jìn)行對(duì)List進(jìn)行remove操作,這樣當(dāng)我們迭代到最后一個(gè)元素時(shí),很明顯此時(shí)List的最后一個(gè)元素為空,那么這時(shí)modCount就會(huì)告訴迭代器,讓其拋出異常ConcurrentModificationException。

如果沒(méi)有這一個(gè)變量,那么系統(tǒng)肯定會(huì)報(bào)異常ArrayIndexOutOfBoundsException,這樣的異常顯然不是應(yīng)該出現(xiàn)的(這些運(yùn)行時(shí)錯(cuò)誤都是使用者的邏輯錯(cuò)誤導(dǎo)致的,我們的JDK那么高端,不會(huì)出現(xiàn)使用錯(cuò)誤,我們只拋出使用者造成的錯(cuò)誤,而這個(gè)錯(cuò)誤是設(shè)計(jì)者應(yīng)該考慮的),為了避免出現(xiàn)這樣的異常,定義了檢查。

(引用自:郭無(wú)心,詳情可以看他在知乎的回答:https://www.zhihu.com/question/24086463/answer/64717159)。

publicvoidtrimToSize(){

modCount++;

//如果size小于length

if(size<elementData.length){

//重新將elementData設(shè)置大小為size

elementData=(size==0)

?EMPTY_ELEMENTDATA

:Arrays.copyOf(elementData,size);

}

}

2.size()

說(shuō)明:返回ArrayList的大小

源碼解釋:直接返回size

publicintsize(){

returnsize;

}

3.isEmpty()

說(shuō)明:返回是否為空

**源碼解釋:**直接返回判斷size==0

publicbooleanisEmpty(){

returnsize==0;

}

4.indexOf(Objecto)

說(shuō)明:對(duì)象o在ArrayList中的下標(biāo)位置,如果存在返回位置i,不存在返回-1

源碼解釋:遍歷ArrayList的大小,比較o和容器內(nèi)的元素,若相等,則返回位置i,若遍歷完都不相等,返回-1

publicintindexOf(Objecto){

if(o==null){

for(inti=0;i<size;i++)

if(elementData[i]==null)

returni;

}else{

for(inti=0;i<size;i++)

if(o.equals(elementData[i]))

returni;

}

return-1;

}

5.contains(Objecto)

說(shuō)明:是否包含對(duì)象o

源碼解釋:調(diào)用indexOf()方法得到下標(biāo),存在則下標(biāo)>=0,不存在為-1,即只要比較下標(biāo)和0的大小即可。

publicbooleancontains(Objecto){

returnindexOf(o)>=0;

}

6.lastIndexOf(Objecto)

說(shuō)明:返回容器內(nèi)出現(xiàn)o的最后一個(gè)位置

源碼解釋:從后向前遍歷,得到第一個(gè)出現(xiàn)對(duì)象o的位置,不存在則返回-1

publicintlastIndexOf(Objecto){

if(o==null){

for(inti=size-1;i>=0;i--)

if(elementData[i]==null)

returni;

}else{

for(inti=size-1;i>=0;i--)

if(o.equals(elementData[i]))

returni;

}

return-1;

}

7.clone()

說(shuō)明:返回此ArrayList實(shí)例的淺表副本。

源碼解釋:

publicObjectclone(){

try{

//調(diào)用父類(翻看源碼可見是Object類)的clone方法得到一個(gè)ArrayList副本

ArrayListv=(ArrayList)super.clone();

//調(diào)用Arrays類的copyOf,將ArrayList的elementData數(shù)組賦值給副本的elementData數(shù)組

v.elementData=Arrays.copyOf(elementData,size);

v.modCount=0;

//返回副本v

returnv;

}catch(CloneNotSupportedExceptione){

thrownewInternalError(e);

}

}

8.toArray()

說(shuō)明:ArrayList實(shí)例轉(zhuǎn)換為。

源碼解釋:直接調(diào)用Arrays類的copyOf。

publicObject[]toArray(){

returnArrays.copyOf(elementData,size);

}

9.toArray(T[]a)

說(shuō)明:將ArrayList里面的元素賦值到一個(gè)數(shù)組中去

源碼解釋:如果a的長(zhǎng)度小于ArrayList的長(zhǎng)度,直接調(diào)用Arrays類的copyOf,返回一個(gè)比a數(shù)組長(zhǎng)度要大的新數(shù)組,里面元素就是ArrayList里面的元素;如果a的長(zhǎng)度比ArrayList的長(zhǎng)度大,那么就調(diào)用System.arraycopy,將ArrayList的elementData數(shù)組賦值到a數(shù)組,然后把a(bǔ)數(shù)組的size位置賦值為空。

publicT[]toArray(T[]a){

if(a.length<size)

//Makeanewarrayofa'sruntimetype,butmycontents:

return(T[])Arrays.copyOf(elementData,size,a.getClass());

System.arraycopy(elementData,0,a,0,size);

if(a.length>size)

a[size]=null;

returna;

}

10.rangeCheck(intindex)

說(shuō)明:測(cè)試index是否越界

源碼解釋:

privatevoidrangeCheck(intindex){

//如果下標(biāo)超過(guò)ArrayList的數(shù)組長(zhǎng)度

if(index>=size)

//拋出IndexOutOfBoundsException異常

thrownewIndexOutOfBoundsException(outOfBoundsMsg(index));

}

11.get(intindex)

說(shuō)明:獲取index位置的元素

源碼解釋:先檢查是否越界,然后返回ArrayList的elementData數(shù)組index位置的元素。

publicEget(intindex){

//檢查是否越界

rangeCheck(index);

//返回ArrayList的elementData數(shù)組index位置的元素

returnelementData(index);

}

12.set(intindex,Eelement)

說(shuō)明:設(shè)置index位置的元素值了element,返回該位置的之前的值

源碼解釋:

publicEset(intindex,Eelement){

//檢查是否越界

rangeCheck(index);

//調(diào)用elementData(index)獲取到當(dāng)前位置的值

EoldValue=elementData(index);

//將element賦值到ArrayList的elementData數(shù)組的第index位置

elementData[index]=element;

returnoldValue;

}

13.ensureCapacityInternal(intminCapacity)

說(shuō)明:得到最小擴(kuò)容量

源碼解釋:

privatevoidensureCapacityInternal(intminCapacity){

if(elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA){

//獲取默認(rèn)的容量和傳入?yún)?shù)的較大值

minCapacity=Math.max(DEFAULT_CAPACITY,minCapacity);

}

ensureExplicitCapacity(minCapacity);

}

14.ensureExplicitCapacity(intminCapacity)

說(shuō)明:判斷是否需要擴(kuò)容

源碼解釋:

privatevoidensureExplicitCapacity(intminCapacity){

modCount++;

//如果最小需要空間比elementData的內(nèi)存空間要大,則需要擴(kuò)容

if(minCapacity-elementData.length>0)

grow(minCapacity);

}

15.grow()方法

說(shuō)明:幫助ArrayList動(dòng)態(tài)擴(kuò)容的核心方法

源碼解釋:

//MAX_VALUE為231-1,MAX_ARRAY_SIZE就是獲取Java中int的最大限制,以防止越界

privatestaticfinalintMAX_ARRAY_SIZE=Integer.MAX_VALUE-8;

privatevoidgrow(intminCapacity){

//獲取到ArrayList中elementData數(shù)組的內(nèi)存空間長(zhǎng)度

intoldCapacity=elementData.length;

//擴(kuò)容至原來(lái)的1.5倍

intnewCapacity=oldCapacity+(oldCapacity>>1);

//再判斷一下新數(shù)組的容量夠不夠,夠了就直接使用這個(gè)長(zhǎng)度創(chuàng)建新數(shù)組,

//不夠就將數(shù)組長(zhǎng)度設(shè)置為需要的長(zhǎng)度

if(newCapacity-minCapacity<0)

newCapacity=minCapacity;

//判斷有沒(méi)超過(guò)最大限制

if(newCapacity-MAX_ARRAY_SIZE>0)

newCapacity=hugeCapacity(minCapacity);

//調(diào)用Arrays.copyOf方法將elementData數(shù)組指向新的內(nèi)存空間時(shí)newCapacity的連續(xù)空間

//并將elementData的數(shù)據(jù)復(fù)制到新的內(nèi)存空間

elementData=Arrays.copyOf(elementData,newCapacity);

}

16.add(Ee)

說(shuō)明:添加元素e

源碼解釋:

publicbooleanadd(Ee){

//擴(kuò)容

ensureCapacityInternal(size+1);

//將e賦值給elementData的size+1的位置。

elementData[size++]=e;

returntrue;

}

17.add(intindex,Eelement)

說(shuō)明:在ArrayList的index位置,添加元素element

源碼解釋:

publicvoidadd(intindex,Eelement){

//判斷index是否越界

rangeCheckForAdd(index);

//擴(kuò)容

ensureCapacityInternal(size+1);

//將elementData從index位置開始,復(fù)制到elementData的index+1開始的連續(xù)空間

System.arraycopy(elementData,index,elementData,index+1,

size-index);

//在elementData的index位置賦值element

elementData[index]=element;

//ArrayList的大小加一

size++;

}

18.remove(intindex)

說(shuō)明:在ArrayList的移除index位置的元素

源碼解釋:

publicEremove(intindex){

//判斷是否越界

rangeCheck(index);

modCount++;

//讀取舊值

EoldValue=elementData(index);

//獲取index位置開始到最后一個(gè)位置的個(gè)數(shù)

intnumMoved=size-index-1;

if(numMoved>0)

//將elementData數(shù)組index+1位置開始拷貝到elementData從index開始的空間

System.arraycopy(elementData,index+1,elementData,index,

numMoved);

//使size-1,設(shè)置elementData的size位置為空,讓GC來(lái)清理內(nèi)存空間

elementData[--size]=null;//cleartoletGCdoitswork

returnoldValue;

}

19.remove(Objecto)

說(shuō)明:在ArrayList的移除對(duì)象為O的元素,跟indexOf方法思想基本一致

源碼解釋:

publicbooleanremove(Objecto){

if(o==null){

for(intindex=0;index<size;index++)

if(elementData[index]==null){

fastRemove(index);

returntrue;

}

}else{

for(intindex=0;index<size;index++)

if(o.equals(elementData[index])){

fastRemove(index);

returntrue;

}

}

returnfalse;

}

20.clear()

說(shuō)明:設(shè)置全部元素為null值,并設(shè)置size為0。

源碼解釋:可見clear操作并不是從空間內(nèi)刪除,只是設(shè)置為null值,等待垃圾回收機(jī)制來(lái)回收而已,把size設(shè)置為0,以便我們不會(huì)瀏覽到null值的內(nèi)存空間。

publicvoidclear(){

modCount++;

//cleartoletGCdoitswork

for(inti=0;i<size;i++)

elementData[i]=null;

size=0;

}

21.addAll(Collectionc)

說(shuō)明:將Collectionc的全部元素添加到ArrayList中

源碼解釋:

publicbooleanaddAll(Collectionc){

//將c轉(zhuǎn)換為數(shù)組a

Object[]a=c.toArray();

//獲取a占的內(nèi)存空間長(zhǎng)度賦值給numNew

intnumNew=a.length;

//擴(kuò)容至size+numNew

ensureCapacityInternal(size+numNew);//IncrementsmodCount

//將a的第0位開始拷貝至elementData的size位開始,拷貝長(zhǎng)度為numNew

System.arraycopy(a,0,elementData,size,numNew);

//將size增加numNew

size+=numNew;

//如果c為空,返回false,c不為空,返回true

returnnumNew!=0;

}

22.addAll(intindex,Collectionc)

說(shuō)明:從第index位開始,將c全部拷貝到ArrayList

源碼解釋:

publicbooleanaddAll(intindex,Collectionc){

//判斷index大于size或者是小于0,如果是,則拋出IndexOutOfBoundsException異常

rangeCheckForAdd(index);

//將c轉(zhuǎn)換為數(shù)組a

Object[]a=c.toArray();

intnumNew=a.length;

//擴(kuò)容至size+numNew

ensureCapacityInternal(size+numNew);//IncrementsmodCount

//獲取需要添加的個(gè)數(shù)

intnumMoved=size-index;

if(numMoved>0)

System.arraycopy(elementData,index,elementData,index+numNew,

numMoved);

System.arraycopy(a,0,elementData,index,numNew);

size+=numNew;

returnnumNew!=0;

}

24.batchRemove(Collectionc,booleancomplement)

說(shuō)明:根據(jù)complement值,將ArrayList中包含c中元素的元素刪除或者保留

源碼解釋:

privatebooleanbatchRemove(Collectionc,booleancomplement){

finalObject[]elementData=this.elementData;

//定義一個(gè)w,一個(gè)r,兩個(gè)同時(shí)右移

intr=0,w=0;

booleanmodified=false;

try{

//r先右移

for(;r<size;r++)

//如果c中不包含elementData[r]這個(gè)元素

if(c.contains(elementData[r])==complement)

//則直接將r位置的元素賦值給w位置的元素,w自增

elementData[w++]=elementData[r];

}finally{

//防止拋出異常導(dǎo)致上面r的右移過(guò)程沒(méi)完成

if(r!=size){

//將r未右移完成的位置的元素賦值給w右邊位置的元素

System.arraycopy(elementData,r,

elementData,w,

size-r);

//修改w值增加size-r

w+=size-r;

}

if(w!=size){

//如果有被覆蓋掉的元素,則將w后面的元素都賦值為null

for(inti=w;i<size;i++)

elementData[i]=null;

modCount+=size-w;

//修改size為w

size=w;

modified=true;

}

}

returnmodified;

}

25.removeAll(Collectionc)

說(shuō)明:ArrayList移除c中的所有元素

源碼解釋:

publicbooleanremoveAll(Collectionc){

//如果c為空,則拋出空指針異常

Objects.requireNonNull(c);

//調(diào)用batchRemove移除c中的元素

returnbatchRemove(c,false);

}

26.retainAll(Collectionc)

說(shuō)明:和removeAll相反,僅保留c中所有的元素

源碼解釋:

publicbooleanretainAll(Collectionc){

Objects.requireNonNull(c);

//調(diào)用batchRemove保留c中的元素

returnbatchRemove(c,true);

}

27.iterator()

說(shuō)明:返回一個(gè)Iterator對(duì)象,Itr為ArrayList的一個(gè)內(nèi)部類,其實(shí)現(xiàn)了Iterator接口

publicIteratoriterator(){

returnnewItr();

}

28.listIterator()

說(shuō)明:返回一個(gè)ListIterator對(duì)象,ListItr為ArrayList的一個(gè)內(nèi)部類,其實(shí)現(xiàn)了ListIterator接口

源碼解釋:

publicListIteratorlistIterator(){

returnnewListItr(0);

}

29.listIterator(intindex)

說(shuō)明:返回一個(gè)從index開始的ListIterator對(duì)象

源碼解釋:

publicListIteratorlistIterator(intindex){

if(index<0||index>size)

thrownewIndexOutOfBoundsException("Index:"+index);

returnnewListItr(index);

}

30.subList(intfromIndex,inttoIndex)

說(shuō)明:根據(jù)兩個(gè)參數(shù),獲取到一個(gè)子序列

源碼解釋:

publicListsubList(intfromIndex,inttoIndex){

//檢查異常

subListRangeCheck(fromIndex,toIndex,size);

//調(diào)用SubList類的構(gòu)造方法

returnnewSubList(this,0,fromIndex,toIndex);

}

五、內(nèi)部類

(1)privateclassItrimplementsIterator

(2)privateclassListItrextendsItrimplementsListIterator

(3)privateclassSubListextendsAbstractListimplementsRandomAccess

(4)staticfinalclassArrayListSpliteratorimplementsSpliterator

ArrayList有四個(gè)內(nèi)部類,

其中的Itr是實(shí)現(xiàn)了Iterator接口,同時(shí)重寫了里面的hasNext(),next(),remove()等方法;

其中的ListItr繼承Itr,實(shí)現(xiàn)了ListIterator接口,同時(shí)重寫了hasPrevious(),nextIndex(),

previousIndex(),previous(),set(Ee),add(Ee)等方法,所以這也可以看出了Iterator和ListIterator的區(qū)別,就是ListIterator在Iterator的基礎(chǔ)上增加了添加對(duì)象,修改對(duì)象,逆向遍歷等方法,這些是Iterator不能實(shí)現(xiàn)的。具體可以參考http://blog.csdn.net/a597926661/article/details/7679765。

其中的SubList繼承AbstractList,實(shí)現(xiàn)了RandmAccess接口,類內(nèi)部實(shí)現(xiàn)了對(duì)子序列的增刪改查等方法,但它同時(shí)也充分利用了內(nèi)部類的優(yōu)點(diǎn),就是共享ArrayList的全局變量,例如檢查器變量modCount,數(shù)組elementData等,所以SubList進(jìn)行的增刪改查操作都是對(duì)ArrayList的數(shù)組進(jìn)行的,并沒(méi)有創(chuàng)建新的數(shù)組。
本文是針對(duì)Java1.8的源代碼進(jìn)行解析的,可能會(huì)和其他版本有所出入。

一、繼承和實(shí)現(xiàn)

繼承:AbstractList

實(shí)現(xiàn):List,RandomAccess,Cloneable,Serializable接口

源代碼

publicclassArrayListextendsAbstractList

implementsList,RandomAccess,Cloneable,java.io.Serializable{

}

二、全局變量

1.默認(rèn)容量

privatestaticfinalintDEFAULT_CAPACITY=10;

2.空的對(duì)象數(shù)組

privatestaticfinalObject[]EMPTY_ELEMENTDATA={};

3.默認(rèn)的空數(shù)組

//無(wú)參構(gòu)造函數(shù)創(chuàng)建的數(shù)組

privatestaticfinalObject[]DEFAULTCAPACITY_EMPTY_ELEMENTDATA={};

4.存放數(shù)據(jù)的數(shù)組的緩存變量,不可序列化

transientObject[]elementData;

5.數(shù)組的大小

privateintsize;

三、構(gòu)造方法

1.帶有容量initialCapacity的構(gòu)造方法

源碼解釋:

publicArrayList(intinitialCapacity){

//如果初始化時(shí)ArrayList大小大于0

if(initialCapacity>0){

//new一個(gè)該大小的object數(shù)組賦給elementData

this.elementData=newObject[initialCapacity];

}elseif(initialCapacity==0){//如果大小為0

//將空數(shù)組賦給elementData

this.elementData=EMPTY_ELEMENTDATA;

}else{//小于0

//則拋出IllegalArgumentException異常

thrownewIllegalArgumentException("IllegalCapacity:"+

initialCapacity);

}

}

2.不帶參數(shù)的構(gòu)造方法

源碼解釋:

publicArrayList(){

//直接將空數(shù)組賦給elementData

this.elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

}

3.帶參數(shù)Collection的構(gòu)造方法

源碼解釋:

參數(shù)c為一個(gè)Collection,Collection的實(shí)現(xiàn)類大概有以下幾種常用類型:

List:元素可以重復(fù)的容器

Set:元素不可重復(fù)的容器

Queue:結(jié)構(gòu)是一個(gè)隊(duì)列,先進(jìn)先出

這個(gè)構(gòu)造方法的意思是,將一個(gè)Collection實(shí)現(xiàn)類的對(duì)象轉(zhuǎn)換為一個(gè)ArrayList,但是c容器裝的內(nèi)容

必須為ArrayList裝的內(nèi)容的子類。例如,將一個(gè)裝了String內(nèi)容的HashSet轉(zhuǎn)換為裝了String內(nèi)容的

ArrayList,使得ArrayList的大小和值數(shù)組都是HashSet的大小和值數(shù)組。具體實(shí)現(xiàn)如下代碼,首先調(diào)

用c(Collection的具體實(shí)現(xiàn)類)的toArray方法,具體大家可以看各個(gè)實(shí)現(xiàn)類的toArray方法,但是大

概意思都是將c容器轉(zhuǎn)換為object類型的數(shù)組,因?yàn)樗鼈兊姆祷刂刀际莖bject[]。之于下面的兩個(gè)判斷

是當(dāng)?shù)玫降膃lementData的類名不是Object類名的時(shí)候或者是長(zhǎng)度為0的時(shí)候才會(huì)執(zhí)行。

publicArrayList(Collectionc){

elementData=c.toArray();

if((size=elementData.length)!=0){

if(elementData.getClass()!=Object[].class)

elementData=Arrays.copyOf(elementData,size,Object[].class);

}else{

//replacewithemptyarray.

this.elementData=EMPTY_ELEMENTDATA;

}

}

四、方法

1.trimToSize()

說(shuō)明:將ArrayList的容量設(shè)置為當(dāng)前size的大小。首先需要明確一個(gè)概念,ArrayList的size就是ArrayList的元素個(gè)數(shù),length是ArrayList申請(qǐng)的內(nèi)容空間長(zhǎng)度。ArrayList每次都會(huì)預(yù)申請(qǐng)多一點(diǎn)空間,以便添加元素的時(shí)候不需要每次都進(jìn)行擴(kuò)容操作,例如我們的元素個(gè)數(shù)是10個(gè),它申請(qǐng)的內(nèi)存空間必定會(huì)大于10,即length>size,而這個(gè)方法就是把ArrayList的內(nèi)存空間設(shè)置為size,去除沒(méi)有用到的null值空間。這也就是我們?yōu)槭裁疵看卧讷@取數(shù)據(jù)長(zhǎng)度是都是調(diào)用list.size()而不是list.length()。

源碼解釋:首先modCount是從類java.util.AbstractList繼承的字段,這個(gè)字段主要是為了防止在多線程操作的情況下,List發(fā)生結(jié)構(gòu)性的變化,什么意思呢?就是防止一個(gè)線程正在迭代,另外一個(gè)線程進(jìn)行對(duì)List進(jìn)行remove操作,這樣當(dāng)我們迭代到最后一個(gè)元素時(shí),很明顯此時(shí)List的最后一個(gè)元素為空,那么這時(shí)modCount就會(huì)告訴迭代器,讓其拋出異常ConcurrentModificationException。

如果沒(méi)有這一個(gè)變量,那么系統(tǒng)肯定會(huì)報(bào)異常ArrayIndexOutOfBoundsException,這樣的異常顯然不是應(yīng)該出現(xiàn)的(這些運(yùn)行時(shí)錯(cuò)誤都是使用者的邏輯錯(cuò)誤導(dǎo)致的,我們的JDK那么高端,不會(huì)出現(xiàn)使用錯(cuò)誤,我們只拋出使用者造成的錯(cuò)誤,而這個(gè)錯(cuò)誤是設(shè)計(jì)者應(yīng)該考慮的),為了避免出現(xiàn)這樣的異常,定義了檢查。

(引用自:郭無(wú)心,詳情可以看他在知乎的回答:https://www.zhihu.com/question/24086463/answer/64717159)。

publicvoidtrimToSize(){

modCount++;

//如果size小于length

if(size<elementData.length){

//重新將elementData設(shè)置大小為size

elementData=(size==0)

?EMPTY_ELEMENTDATA

:Arrays.copyOf(elementData,size);

}

}

2.size()

說(shuō)明:返回ArrayList的大小

源碼解釋:直接返回size

publicintsize(){

returnsize;

}

3.isEmpty()

說(shuō)明:返回是否為空

**源碼解釋:**直接返回判斷size==0

publicbooleanisEmpty(){

returnsize==0;

}

4.indexOf(Objecto)

說(shuō)明:對(duì)象o在ArrayList中的下標(biāo)位置,如果存在返回位置i,不存在返回-1

源碼解釋:遍歷ArrayList的大小,比較o和容器內(nèi)的元素,若相等,則返回位置i,若遍歷完都不相等,返回-1

publicintindexOf(Objecto){

if(o==null){

for(inti=0;i<size;i++)

if(elementData[i]==null)

returni;

}else{

for(inti=0;i<size;i++)

if(o.equals(elementData[i]))

returni;

}

return-1;

}

5.contains(Objecto)

說(shuō)明:是否包含對(duì)象o

源碼解釋:調(diào)用indexOf()方法得到下標(biāo),存在則下標(biāo)>=0,不存在為-1,即只要比較下標(biāo)和0的大小即可。

publicbooleancontains(Objecto){

returnindexOf(o)>=0;

}

6.lastIndexOf(Objecto)

說(shuō)明:返回容器內(nèi)出現(xiàn)o的最后一個(gè)位置

源碼解釋:從后向前遍歷,得到第一個(gè)出現(xiàn)對(duì)象o的位置,不存在則返回-1

publicintlastIndexOf(Objecto){

if(o==null){

for(inti=size-1;i>=0;i--)

if(elementData[i]==null)

returni;

}else{

for(inti=size-1;i>=0;i--)

if(o.equals(elementData[i]))

returni;

}

return-1;

}

7.clone()

說(shuō)明:返回此ArrayList實(shí)例的淺表副本。

源碼解釋:

publicObjectclone(){

try{

//調(diào)用父類(翻看源碼可見是Object類)的clone方法得到一個(gè)ArrayList副本

ArrayListv=(ArrayList)super.clone();

//調(diào)用Arrays類的copyOf,將ArrayList的elementData數(shù)組賦值給副本的elementData數(shù)組

v.elementData=Arrays.copyOf(elementData,size);

v.modCount=0;

//返回副本v

returnv;

}catch(CloneNotSupportedExceptione){

thrownewInternalError(e);

}

}

8.toArray()

說(shuō)明:ArrayList實(shí)例轉(zhuǎn)換為。

源碼解釋:直接調(diào)用Arrays類的copyOf。

publicObject[]toArray(){

returnArrays.copyOf(elementData,size);

}

9.toArray(T[]a)

說(shuō)明:將ArrayList里面的元素賦值到一個(gè)數(shù)組中去

源碼解釋:如果a的長(zhǎng)度小于ArrayList的長(zhǎng)度,直接調(diào)用Arrays類的copyOf,返回一個(gè)比a數(shù)組長(zhǎng)度要大的新數(shù)組,里面元素就是ArrayList里面的元素;如果a的長(zhǎng)度比ArrayList的長(zhǎng)度大,那么就調(diào)用System.arraycopy,將ArrayList的elementData數(shù)組賦值到a數(shù)組,然后把a(bǔ)數(shù)組的size位置賦值為空。

publicT[]toArray(T[]a){

if(a.length<size)

//Makeanewarrayofa'sruntimetype,butmycontents:

return(T[])Arrays.copyOf(elementData,size,a.getClass());

System.arraycopy(elementData,0,a,0,size);

if(a.length>size)

a[size]=null;

returna;

}

10.rangeCheck(intindex)

說(shuō)明:測(cè)試index是否越界

源碼解釋:

privatevoidrangeCheck(intindex){

//如果下標(biāo)超過(guò)ArrayList的數(shù)組長(zhǎng)度

if(index>=size)

//拋出IndexOutOfBoundsException異常

thrownewIndexOutOfBoundsException(outOfBoundsMsg(index));

}

11.get(intindex)

說(shuō)明:獲取index位置的元素

源碼解釋:先檢查是否越界,然后返回ArrayList的elementData數(shù)組index位置的元素。

publicEget(intindex){

//檢查是否越界

rangeCheck(index);

//返回ArrayList的elementData數(shù)組index位置的元素

returnelementData(index);

}

12.set(intindex,Eelement)

說(shuō)明:設(shè)置index位置的元素值了element,返回該位置的之前的值

源碼解釋:

publicEset(intindex,Eelement){

//檢查是否越界

rangeCheck(index);

//調(diào)用elementData(index)獲取到當(dāng)前位置的值

EoldValue=elementData(index);

//將element賦值到ArrayList的elementData數(shù)組的第index位置

elementData[index]=element;

returnoldValue;

}

13.ensureCapacityInternal(intminCapacity)

說(shuō)明:得到最小擴(kuò)容量

源碼解釋:

privatevoidensureCapacityInternal(intminCapacity){

if(elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA){

//獲取默認(rèn)的容量和傳入?yún)?shù)的較大值

minCapacity=Math.max(DEFAULT_CAPACITY,minCapacity);

}

ensureExplicitCapacity(minCapacity);

}

14.ensureExplicitCapacity(intminCapacity)

說(shuō)明:判斷是否需要擴(kuò)容

源碼解釋:

privatevoidensureExplicitCapacity(intminCapacity){

modCount++;

//如果最小需要空間比elementData的內(nèi)存空間要大,則需要擴(kuò)容

if(minCapacity-elementData.length>0)

grow(minCapacity);

}

15.grow()方法

說(shuō)明:幫助ArrayList動(dòng)態(tài)擴(kuò)容的核心方法

源碼解釋:

//MAX_VALUE為231-1,MAX_ARRAY_SIZE就是獲取Java中int的最大限制,以防止越界

privatestaticfinalintMAX_ARRAY_SIZE=Integer.MAX_VALUE-8;

privatevoidgrow(intminCapacity){

//獲取到ArrayList中elementData數(shù)組的內(nèi)存空間長(zhǎng)度

intoldCapacity=elementData.length;

//擴(kuò)容至原來(lái)的1.5倍

intnewCapacity=oldCapacity+(oldCapacity>>1);

//再判斷一下新數(shù)組的容量夠不夠,夠了就直接使用這個(gè)長(zhǎng)度創(chuàng)建新數(shù)組,

//不夠就將數(shù)組長(zhǎng)度設(shè)置為需要的長(zhǎng)度

if(newCapacity-minCapacity<0)

newCapacity=minCapacity;

//判斷有沒(méi)超過(guò)最大限制

if(newCapacity-MAX_ARRAY_SIZE>0)

newCapacity=hugeCapacity(minCapacity);

//調(diào)用Arrays.copyOf方法將elementData數(shù)組指向新的內(nèi)存空間時(shí)newCapacity的連續(xù)空間

//并將elementData的數(shù)據(jù)復(fù)制到新的內(nèi)存空間

elementData=Arrays.copyOf(elementData,newCapacity);

}

16.add(Ee)

說(shuō)明:添加元素e

源碼解釋:

publicbooleanadd(Ee){

//擴(kuò)容

ensureCapacityInternal(size+1);

//將e賦值給elementData的size+1的位置。

elementData[size++]=e;

returntrue;

}

17.add(intindex,Eelement)

說(shuō)明:在ArrayList的index位置,添加元素element

源碼解釋:

publicvoidadd(intindex,Eelement){

//判斷index是否越界

rangeCheckForAdd(index);

//擴(kuò)容

ensureCapacityInternal(size+1);

//將elementData從index位置開始,復(fù)制到elementData的index+1開始的連續(xù)空間

System.arraycopy(elementData,index,elementData,index+1,

size-index);

//在elementData的index位置賦值element

elementData[index]=element;

//ArrayList的大小加一

size++;

}

18.remove(intindex)

說(shuō)明:在ArrayList的移除index位置的元素

源碼解釋:

publicEremove(intindex){

//判斷是否越界

rangeCheck(index);

modCount++;

//讀取舊值

EoldValue=elementData(index);

//獲取index位置開始到最后一個(gè)位置的個(gè)數(shù)

intnumMoved=size-index-1;

if(numMoved>0)

//將elementData數(shù)組index+1位置開始拷貝到elementData從index開始的空間

System.arraycopy(elementData,index+1,elementData,index,

numMoved);

//使size-1,設(shè)置elementData的size位置為空,讓GC來(lái)清理內(nèi)存空間

elementData[--size]=null;//cleartoletGCdoitswork

returnoldValue;

}

19.remove(Objecto)

說(shuō)明:在ArrayList的移除對(duì)象為O的元素,跟indexOf方法思想基本一致

源碼解釋:

publicbooleanremove(Objecto){

if(o==null){

for(intindex=0;index<size;index++)

if(elementData[index]==null){

fastRemove(index);

returntrue;

}

}else{

for(intindex=0;index<size;index++)

if(o.equals(elementData[index])){

fastRemove(index);

returntrue;

}

}

returnfalse;

}

20.clear()

說(shuō)明:設(shè)置全部元素為null值,并設(shè)置size為0。

源碼解釋:可見clear操作并不是從空間內(nèi)刪除,只是設(shè)置為null值,等待垃圾回收機(jī)制來(lái)回收而已,把size設(shè)置為0,以便我們不會(huì)瀏覽到null值的內(nèi)存空間。

publicvoidclear(){

modCount++;

//cleartoletGCdoitswork

for(inti=0;i<size;i++)

elementData[i]=null;

size=0;

}

21.addAll(Collectionc)

說(shuō)明:將Collectionc的全部元素添加到ArrayList中

源碼解釋:

publicbooleanaddAll(Collectionc){

//將c轉(zhuǎn)換為數(shù)組a

Object[]a=c.toArray();

//獲取a占的內(nèi)存空間長(zhǎng)度賦值給numNew

intnumNew=a.length;

//擴(kuò)容至size+numNew

ensureCapacityInternal(size+numNew);//IncrementsmodCount

//將a的第0位開始拷貝至elementData的size位開始,拷貝長(zhǎng)度為numNew

System.arraycopy(a,0,elementData,size,numNew);

//將size增加numNew

size+=numNew;

//如果c為空,返回false,c不為空,返回true

returnnumNew!=0;

}

22.addAll(intindex,Collectionc)

說(shuō)明:從第index位開始,將c全部拷貝到ArrayList

源碼解釋:

publicbooleanaddAll(intindex,Collectionc){

//判斷index大于size或者是小于0,如果是,則拋出IndexOutOfBoundsException異常

rangeCheckForAdd(index);

//將c轉(zhuǎn)換為數(shù)組a

Object[]a=c.toArray();

intnumNew=a.length;

//擴(kuò)容至size+numNew

ensureCapacityInternal(size+numNew);//IncrementsmodCount

//獲取需要添加的個(gè)數(shù)

intnumMoved=size-index;

if(numMoved>0)

System.arraycopy(elementData,index,elementData,index+numNew,

numMoved);

System.arraycopy(a,0,elementData,index,numNew);

size+=numNew;

returnnumNew!=0;

}

24.batchRemove(Collectionc,booleancomplement)

說(shuō)明:根據(jù)complement值,將ArrayList中包含c中元素的元素刪除或者保留

源碼解釋:

privatebooleanbatchRemove(Collectionc,booleancomplement){

finalObject[]elementData=this.elementData;

//定義一個(gè)w,一個(gè)r,兩個(gè)同時(shí)右移

intr=0,w=0;

booleanmodified=false;

try{

//r先右移

for(;r<size;r++)

//如果c中不包含elementData[r]這個(gè)元素

if(c.contains(elementData[r])==complement)

//則直接將r位置的元素賦值給w位置的元素,w自增

elementData[w++]=elementData[r];

}finally{

//防止拋出異常導(dǎo)致上面r的右移過(guò)程沒(méi)完成

if(r!=size){

//將r未右移完成的位置的元素賦值給w右邊位置的元素

System.arraycopy(elementData,r,

elementData,w,

size-r);

//修改w值增加size-r

w+=size-r;

}

if(w!=size){

//如果有被覆蓋掉的元素,則將w后面的元素都賦值為null

for(inti=w;i<size;i++)

elementData[i]=null;

modCount+=size-w;

//修改size為w

size=w;

modified=true;

}

}

returnmodified;

}

25.removeAll(Collectionc)

說(shuō)明:ArrayList移除c中的所有元素

源碼解釋:

publicbooleanremoveAll(Collectionc){

//如果c為空,則拋出空指針異常

Objects.requireNonNull(c);

//調(diào)用batchRemove移除c中的元素

returnbatchRemove(c,false);

}

26.retainAll(Collectionc)

說(shuō)明:和removeAll相反,僅保留c中所有的元素

源碼解釋:

publicbooleanretainAll(Collectionc){

Objects.requireNonNull(c);

//調(diào)用batchRemove保留c中的元素

returnbatchRemove(c,true);

}

27.iterator()

說(shuō)明:返回一個(gè)Iterator對(duì)象,Itr為ArrayList的一個(gè)內(nèi)部類,其實(shí)現(xiàn)了Iterator接口

publicIteratoriterator(){

returnnewItr();

}

28.listIterator()

說(shuō)明:返回一個(gè)ListIterator對(duì)象,ListItr為ArrayList的一個(gè)內(nèi)部類,其實(shí)現(xiàn)了ListIterator接口

源碼解釋:

publicListIteratorlistIterator(){

returnnewListItr(0);

}

29.listIterator(intindex)

說(shuō)明:返回一個(gè)從index開始的ListIterator對(duì)象

源碼解釋:

publicListIteratorlistIterator(intindex){

if(index<0||index>size)

thrownewIndexOutOfBoundsException("Index:"+index);

returnnewListItr(index);

}

30.subList(intfromIndex,inttoIndex)

說(shuō)明:根據(jù)兩個(gè)參數(shù),獲取到一個(gè)子序列

源碼解釋:

publicListsubList(intfromIndex,inttoIndex){

//檢查異常

subListRangeCheck(fromIndex,toIndex,size);

//調(diào)用SubList類的構(gòu)造方法

returnnewSubList(this,0,fromIndex,toIndex);

}

五、內(nèi)部類

(1)privateclassItrimplementsIterator

(2)privateclassListItrextendsItrimplementsListIterator

(3)privateclassSubListextendsAbstractListimplementsRandomAccess

(4)staticfinalclassArrayListSpliteratorimplementsSpliterator

ArrayList有四個(gè)內(nèi)部類,

其中的Itr是實(shí)現(xiàn)了Iterator接口,同時(shí)重寫了里面的hasNext(),next(),remove()等方法;

其中的ListItr繼承Itr,實(shí)現(xiàn)了ListIterator接口,同時(shí)重寫了hasPrevious(),nextIndex(),

previousIndex(),previous(),set(Ee),add(Ee)等方法,所以這也可以看出了Iterator和ListIterator的區(qū)別,就是ListIterator在Iterator的基礎(chǔ)上增加了添加對(duì)象,修改對(duì)象,逆向遍歷等方法,這些是Iterator不能實(shí)現(xiàn)的。具體可以參考http://blog.csdn.net/a597926661/article/details/7679765。

其中的SubList繼承AbstractList,實(shí)現(xiàn)了RandmAccess接口,類內(nèi)部實(shí)現(xiàn)了對(duì)子序列的增刪改查等方法,但它同時(shí)也充分利用了內(nèi)部類的優(yōu)點(diǎn),就是共享ArrayList的全局變量,例如檢查器變量modCount,數(shù)組elementData等,所以SubList進(jìn)行的增刪改查操作都是對(duì)ArrayList的數(shù)組進(jìn)行的,并沒(méi)有創(chuàng)建新的數(shù)組。


以上就是關(guān)于Java培訓(xùn)之容器類ArrayList源碼分析的詳細(xì)介紹,最后想要了解更多關(guān)于JavaEE開發(fā)問(wèn)題的小伙伴可以登錄扣丁學(xué)堂官網(wǎng)咨詢??鄱W(xué)堂是專業(yè)的JavaEE培訓(xùn)機(jī)構(gòu),不僅有專業(yè)的老師和與時(shí)俱進(jìn)的課程體系,還有大量的Java視頻教程供學(xué)員觀看學(xué)習(xí),想要學(xué)好JavaEE的小伙伴抓緊時(shí)間行動(dòng)吧??鄱W(xué)堂java技術(shù)交流群:487098661。微信號(hào):codingbb

*博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。



關(guān)鍵詞:

相關(guān)推薦

技術(shù)專區(qū)

關(guān)閉