扣丁學(xué)堂Java培訓(xùn)之容器類ArrayList源碼分析
本文是針對(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)系工作人員刪除。