Java培訓之容器類ArrayList源碼分析
2018-04-23 10:27:44
1708瀏覽
本文是針對Java1.8的源代碼進行解析的,可能會和其他版本有所出入。
一、繼承和實現(xiàn)
繼承:AbstractList
實現(xiàn):List,RandomAccess,Cloneable,Serializable接口
publicclassArrayListextendsAbstractList
implementsList,RandomAccess,Cloneable,java.io.Serializable{
}
二、全局變量
1.默認容量
privatestaticfinalintDEFAULT_CAPACITY=10;
2.空的對象數(shù)組
privatestaticfinalObject[]EMPTY_ELEMENTDATA={};
3.默認的空數(shù)組
//無參構造函數(shù)創(chuàng)建的數(shù)組
privatestaticfinalObject[]DEFAULTCAPACITY_EMPTY_ELEMENTDATA={};
4.存放數(shù)據(jù)的數(shù)組的緩存變量,不可序列化
transientObject[]elementData;
5.數(shù)組的大小
privateintsize;
三、構造方法
1.帶有容量initialCapacity的構造方法
源碼解釋:
publicArrayList(intinitialCapacity){
//如果初始化時ArrayList大小大于0
if(initialCapacity>0){
//new一個該大小的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ù)的構造方法
源碼解釋:
publicArrayList(){
//直接將空數(shù)組賦給elementData
this.elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
3.帶參數(shù)Collection的構造方法
源碼解釋:
參數(shù)c為一個Collection,Collection的實現(xiàn)類大概有以下幾種常用類型:
List:元素可以重復的容器
Set:元素不可重復的容器
Queue:結構是一個隊列,先進先出
這個構造方法的意思是,將一個Collection實現(xiàn)類的對象轉換為一個ArrayList,但是c容器裝的內(nèi)容
必須為ArrayList裝的內(nèi)容的子類。例如,將一個裝了String內(nèi)容的HashSet轉換為裝了String內(nèi)容的
ArrayList,使得ArrayList的大小和值數(shù)組都是HashSet的大小和值數(shù)組。具體實現(xiàn)如下代碼,首先調(diào)
用c(Collection的具體實現(xiàn)類)的toArray方法,具體大家可以看各個實現(xiàn)類的toArray方法,但是大
概意思都是將c容器轉換為object類型的數(shù)組,因為它們的返回值都是object[]。之于下面的兩個判斷
是當?shù)玫降膃lementData的類名不是Object類名的時候或者是長度為0的時候才會執(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()
說明:將ArrayList的容量設置為當前size的大小。首先需要明確一個概念,ArrayList的size就是ArrayList的元素個數(shù),length是ArrayList申請的內(nèi)容空間長度。ArrayList每次都會預申請多一點空間,以便添加元素的時候不需要每次都進行擴容操作,例如我們的元素個數(shù)是10個,它申請的內(nèi)存空間必定會大于10,即length>size,而這個方法就是把ArrayList的內(nèi)存空間設置為size,去除沒有用到的null值空間。這也就是我們?yōu)槭裁疵看卧讷@取數(shù)據(jù)長度是都是調(diào)用list.size()而不是list.length()。
源碼解釋:首先modCount是從類java.util.AbstractList繼承的字段,這個字段主要是為了防止在多線程操作的情況下,List發(fā)生結構性的變化,什么意思呢?就是防止一個線程正在迭代,另外一個線程進行對List進行remove操作,這樣當我們迭代到最后一個元素時,很明顯此時List的最后一個元素為空,那么這時modCount就會告訴迭代器,讓其拋出異常ConcurrentModificationException。
如果沒有這一個變量,那么系統(tǒng)肯定會報異常ArrayIndexOutOfBoundsException,這樣的異常顯然不是應該出現(xiàn)的(這些運行時錯誤都是使用者的邏輯錯誤導致的,我們的JDK那么高端,不會出現(xiàn)使用錯誤,我們只拋出使用者造成的錯誤,而這個錯誤是設計者應該考慮的),為了避免出現(xiàn)這樣的異常,定義了檢查。
(引用自:郭無心,詳情可以看他在知乎的回答:https://www.zhihu.com/question/24086463/answer/64717159)。
publicvoidtrimToSize(){
modCount++;
//如果size小于length
if(size<elementData.length){
//重新將elementData設置大小為size
elementData=(size==0)
?EMPTY_ELEMENTDATA
:Arrays.copyOf(elementData,size);
}
}
2.size()
說明:返回ArrayList的大小
源碼解釋:直接返回size
publicintsize(){
returnsize;
}
3.isEmpty()
說明:返回是否為空
**源碼解釋:**直接返回判斷size==0
publicbooleanisEmpty(){
returnsize==0;
}
4.indexOf(Objecto)
說明:對象o在ArrayList中的下標位置,如果存在返回位置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)
說明:是否包含對象o
源碼解釋:調(diào)用indexOf()方法得到下標,存在則下標>=0,不存在為-1,即只要比較下標和0的大小即可。
publicbooleancontains(Objecto){
returnindexOf(o)>=0;
}
6.lastIndexOf(Objecto)
說明:返回容器內(nèi)出現(xiàn)o的最后一個位置
源碼解釋:從后向前遍歷,得到第一個出現(xiàn)對象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()
說明:返回此ArrayList實例的淺表副本。
源碼解釋:
publicObjectclone(){
try{
//調(diào)用父類(翻看源碼可見是Object類)的clone方法得到一個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()
說明:ArrayList實例轉換為。
源碼解釋:直接調(diào)用Arrays類的copyOf。
publicObject[]toArray(){
returnArrays.copyOf(elementData,size);
}
9.toArray(T[]a)
說明:將ArrayList里面的元素賦值到一個數(shù)組中去
源碼解釋:如果a的長度小于ArrayList的長度,直接調(diào)用Arrays類的copyOf,返回一個比a數(shù)組長度要大的新數(shù)組,里面元素就是ArrayList里面的元素;如果a的長度比ArrayList的長度大,那么就調(diào)用System.arraycopy,將ArrayList的elementData數(shù)組賦值到a數(shù)組,然后把a數(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)
說明:測試index是否越界
源碼解釋:
privatevoidrangeCheck(intindex){
//如果下標超過ArrayList的數(shù)組長度
if(index>=size)
//拋出IndexOutOfBoundsException異常
thrownewIndexOutOfBoundsException(outOfBoundsMsg(index));
}
11.get(intindex)
說明:獲取index位置的元素
源碼解釋:先檢查是否越界,然后返回ArrayList的elementData數(shù)組index位置的元素。
publicEget(intindex){
//檢查是否越界
rangeCheck(index);
//返回ArrayList的elementData數(shù)組index位置的元素
returnelementData(index);
}
12.set(intindex,Eelement)
說明:設置index位置的元素值了element,返回該位置的之前的值
源碼解釋:
publicEset(intindex,Eelement){
//檢查是否越界
rangeCheck(index);
//調(diào)用elementData(index)獲取到當前位置的值
EoldValue=elementData(index);
//將element賦值到ArrayList的elementData數(shù)組的第index位置
elementData[index]=element;
returnoldValue;
}
13.ensureCapacityInternal(intminCapacity)
說明:得到最小擴容量
源碼解釋:
privatevoidensureCapacityInternal(intminCapacity){
if(elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA){
//獲取默認的容量和傳入?yún)?shù)的較大值
minCapacity=Math.max(DEFAULT_CAPACITY,minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
14.ensureExplicitCapacity(intminCapacity)
說明:判斷是否需要擴容
源碼解釋:
privatevoidensureExplicitCapacity(intminCapacity){
modCount++;
//如果最小需要空間比elementData的內(nèi)存空間要大,則需要擴容
if(minCapacity-elementData.length>0)
grow(minCapacity);
}
15.grow()方法
說明:幫助ArrayList動態(tài)擴容的核心方法
源碼解釋:
//MAX_VALUE為231-1,MAX_ARRAY_SIZE就是獲取Java中int的最大限制,以防止越界
privatestaticfinalintMAX_ARRAY_SIZE=Integer.MAX_VALUE-8;
privatevoidgrow(intminCapacity){
//獲取到ArrayList中elementData數(shù)組的內(nèi)存空間長度
intoldCapacity=elementData.length;
//擴容至原來的1.5倍
intnewCapacity=oldCapacity+(oldCapacity>>1);
//再判斷一下新數(shù)組的容量夠不夠,夠了就直接使用這個長度創(chuàng)建新數(shù)組,
//不夠就將數(shù)組長度設置為需要的長度
if(newCapacity-minCapacity<0)
newCapacity=minCapacity;
//判斷有沒超過最大限制
if(newCapacity-MAX_ARRAY_SIZE>0)
newCapacity=hugeCapacity(minCapacity);
//調(diào)用Arrays.copyOf方法將elementData數(shù)組指向新的內(nèi)存空間時newCapacity的連續(xù)空間
//并將elementData的數(shù)據(jù)復制到新的內(nèi)存空間
elementData=Arrays.copyOf(elementData,newCapacity);
}
16.add(Ee)
說明:添加元素e
源碼解釋:
publicbooleanadd(Ee){
//擴容
ensureCapacityInternal(size+1);
//將e賦值給elementData的size+1的位置。
elementData[size++]=e;
returntrue;
}
17.add(intindex,Eelement)
說明:在ArrayList的index位置,添加元素element
源碼解釋:
publicvoidadd(intindex,Eelement){
//判斷index是否越界
rangeCheckForAdd(index);
//擴容
ensureCapacityInternal(size+1);
//將elementData從index位置開始,復制到elementData的index+1開始的連續(xù)空間
System.arraycopy(elementData,index,elementData,index+1,
size-index);
//在elementData的index位置賦值element
elementData[index]=element;
//ArrayList的大小加一
size++;
}
18.remove(intindex)
說明:在ArrayList的移除index位置的元素
源碼解釋:
publicEremove(intindex){
//判斷是否越界
rangeCheck(index);
modCount++;
//讀取舊值
EoldValue=elementData(index);
//獲取index位置開始到最后一個位置的個數(shù)
intnumMoved=size-index-1;
if(numMoved>0)
//將elementData數(shù)組index+1位置開始拷貝到elementData從index開始的空間
System.arraycopy(elementData,index+1,elementData,index,
numMoved);
//使size-1,設置elementData的size位置為空,讓GC來清理內(nèi)存空間
elementData[--size]=null;//cleartoletGCdoitswork
returnoldValue;
}
19.remove(Objecto)
說明:在ArrayList的移除對象為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()
說明:設置全部元素為null值,并設置size為0。
源碼解釋:可見clear操作并不是從空間內(nèi)刪除,只是設置為null值,等待垃圾回收機制來回收而已,把size設置為0,以便我們不會瀏覽到null值的內(nèi)存空間。
publicvoidclear(){
modCount++;
//cleartoletGCdoitswork
for(inti=0;i<size;i++)
elementData[i]=null;
size=0;
}
21.addAll(Collectionc)
說明:將Collectionc的全部元素添加到ArrayList中
源碼解釋:
publicbooleanaddAll(Collectionc){
//將c轉換為數(shù)組a
Object[]a=c.toArray();
//獲取a占的內(nèi)存空間長度賦值給numNew
intnumNew=a.length;
//擴容至size+numNew
ensureCapacityInternal(size+numNew);//IncrementsmodCount
//將a的第0位開始拷貝至elementData的size位開始,拷貝長度為numNew
System.arraycopy(a,0,elementData,size,numNew);
//將size增加numNew
size+=numNew;
//如果c為空,返回false,c不為空,返回true
returnnumNew!=0;
}
22.addAll(intindex,Collectionc)
說明:從第index位開始,將c全部拷貝到ArrayList
源碼解釋:
publicbooleanaddAll(intindex,Collectionc){
//判斷index大于size或者是小于0,如果是,則拋出IndexOutOfBoundsException異常
rangeCheckForAdd(index);
//將c轉換為數(shù)組a
Object[]a=c.toArray();
intnumNew=a.length;
//擴容至size+numNew
ensureCapacityInternal(size+numNew);//IncrementsmodCount
//獲取需要添加的個數(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)
說明:根據(jù)complement值,將ArrayList中包含c中元素的元素刪除或者保留
源碼解釋:
privatebooleanbatchRemove(Collectionc,booleancomplement){
finalObject[]elementData=this.elementData;
//定義一個w,一個r,兩個同時右移
intr=0,w=0;
booleanmodified=false;
try{
//r先右移
for(;r<size;r++)
//如果c中不包含elementData[r]這個元素
if(c.contains(elementData[r])==complement)
//則直接將r位置的元素賦值給w位置的元素,w自增
elementData[w++]=elementData[r];
}finally{
//防止拋出異常導致上面r的右移過程沒完成
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)
說明:ArrayList移除c中的所有元素
源碼解釋:
publicbooleanremoveAll(Collectionc){
//如果c為空,則拋出空指針異常
Objects.requireNonNull(c);
//調(diào)用batchRemove移除c中的元素
returnbatchRemove(c,false);
}
26.retainAll(Collectionc)
說明:和removeAll相反,僅保留c中所有的元素
源碼解釋:
publicbooleanretainAll(Collectionc){
Objects.requireNonNull(c);
//調(diào)用batchRemove保留c中的元素
returnbatchRemove(c,true);
}
27.iterator()
說明:返回一個Iterator對象,Itr為ArrayList的一個內(nèi)部類,其實現(xiàn)了Iterator接口
publicIteratoriterator(){
returnnewItr();
}
28.listIterator()
說明:返回一個ListIterator對象,ListItr為ArrayList的一個內(nèi)部類,其實現(xiàn)了ListIterator接口
源碼解釋:
publicListIteratorlistIterator(){
returnnewListItr(0);
}
29.listIterator(intindex)
說明:返回一個從index開始的ListIterator對象
源碼解釋:
publicListIteratorlistIterator(intindex){
if(index<0||index>size)
thrownewIndexOutOfBoundsException("Index:"+index);
returnnewListItr(index);
}
30.subList(intfromIndex,inttoIndex)
說明:根據(jù)兩個參數(shù),獲取到一個子序列
源碼解釋:
publicListsubList(intfromIndex,inttoIndex){
//檢查異常
subListRangeCheck(fromIndex,toIndex,size);
//調(diào)用SubList類的構造方法
returnnewSubList(this,0,fromIndex,toIndex);
}
五、內(nèi)部類
(1)privateclassItrimplementsIterator
(2)privateclassListItrextendsItrimplementsListIterator
(3)privateclassSubListextendsAbstractListimplementsRandomAccess
(4)staticfinalclassArrayListSpliteratorimplementsSpliterator
ArrayList有四個內(nèi)部類,
其中的Itr是實現(xiàn)了Iterator接口,同時重寫了里面的hasNext(),next(),remove()等方法;
其中的ListItr繼承Itr,實現(xiàn)了ListIterator接口,同時重寫了hasPrevious(),nextIndex(),
previousIndex(),previous(),set(Ee),add(Ee)等方法,所以這也可以看出了Iterator和ListIterator的區(qū)別,就是ListIterator在Iterator的基礎上增加了添加對象,修改對象,逆向遍歷等方法,這些是Iterator不能實現(xiàn)的。具體可以參考http://blog.csdn.net/a597926661/article/details/7679765。
其中的SubList繼承AbstractList,實現(xiàn)了RandmAccess接口,類內(nèi)部實現(xiàn)了對子序列的增刪改查等方法,但它同時也充分利用了內(nèi)部類的優(yōu)點,就是共享ArrayList的全局變量,例如檢查器變量modCount,數(shù)組elementData等,所以SubList進行的增刪改查操作都是對ArrayList的數(shù)組進行的,并沒有創(chuàng)建新的數(shù)組。
本文是針對Java1.8的源代碼進行解析的,可能會和其他版本有所出入。
一、繼承和實現(xiàn)
繼承:AbstractList
實現(xiàn):List,RandomAccess,Cloneable,Serializable接口
源代碼
publicclassArrayListextendsAbstractList
implementsList,RandomAccess,Cloneable,java.io.Serializable{
}
二、全局變量
1.默認容量
privatestaticfinalintDEFAULT_CAPACITY=10;
2.空的對象數(shù)組
privatestaticfinalObject[]EMPTY_ELEMENTDATA={};
3.默認的空數(shù)組
//無參構造函數(shù)創(chuàng)建的數(shù)組
privatestaticfinalObject[]DEFAULTCAPACITY_EMPTY_ELEMENTDATA={};
4.存放數(shù)據(jù)的數(shù)組的緩存變量,不可序列化
transientObject[]elementData;
5.數(shù)組的大小
privateintsize;
三、構造方法
1.帶有容量initialCapacity的構造方法
源碼解釋:
publicArrayList(intinitialCapacity){
//如果初始化時ArrayList大小大于0
if(initialCapacity>0){
//new一個該大小的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ù)的構造方法
源碼解釋:
publicArrayList(){
//直接將空數(shù)組賦給elementData
this.elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
3.帶參數(shù)Collection的構造方法
源碼解釋:
參數(shù)c為一個Collection,Collection的實現(xiàn)類大概有以下幾種常用類型:
List:元素可以重復的容器
Set:元素不可重復的容器
Queue:結構是一個隊列,先進先出
這個構造方法的意思是,將一個Collection實現(xiàn)類的對象轉換為一個ArrayList,但是c容器裝的內(nèi)容
必須為ArrayList裝的內(nèi)容的子類。例如,將一個裝了String內(nèi)容的HashSet轉換為裝了String內(nèi)容的
ArrayList,使得ArrayList的大小和值數(shù)組都是HashSet的大小和值數(shù)組。具體實現(xiàn)如下代碼,首先調(diào)
用c(Collection的具體實現(xiàn)類)的toArray方法,具體大家可以看各個實現(xiàn)類的toArray方法,但是大
概意思都是將c容器轉換為object類型的數(shù)組,因為它們的返回值都是object[]。之于下面的兩個判斷
是當?shù)玫降膃lementData的類名不是Object類名的時候或者是長度為0的時候才會執(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()
說明:將ArrayList的容量設置為當前size的大小。首先需要明確一個概念,ArrayList的size就是ArrayList的元素個數(shù),length是ArrayList申請的內(nèi)容空間長度。ArrayList每次都會預申請多一點空間,以便添加元素的時候不需要每次都進行擴容操作,例如我們的元素個數(shù)是10個,它申請的內(nèi)存空間必定會大于10,即length>size,而這個方法就是把ArrayList的內(nèi)存空間設置為size,去除沒有用到的null值空間。這也就是我們?yōu)槭裁疵看卧讷@取數(shù)據(jù)長度是都是調(diào)用list.size()而不是list.length()。
源碼解釋:首先modCount是從類java.util.AbstractList繼承的字段,這個字段主要是為了防止在多線程操作的情況下,List發(fā)生結構性的變化,什么意思呢?就是防止一個線程正在迭代,另外一個線程進行對List進行remove操作,這樣當我們迭代到最后一個元素時,很明顯此時List的最后一個元素為空,那么這時modCount就會告訴迭代器,讓其拋出異常ConcurrentModificationException。
如果沒有這一個變量,那么系統(tǒng)肯定會報異常ArrayIndexOutOfBoundsException,這樣的異常顯然不是應該出現(xiàn)的(這些運行時錯誤都是使用者的邏輯錯誤導致的,我們的JDK那么高端,不會出現(xiàn)使用錯誤,我們只拋出使用者造成的錯誤,而這個錯誤是設計者應該考慮的),為了避免出現(xiàn)這樣的異常,定義了檢查。
(引用自:郭無心,詳情可以看他在知乎的回答:https://www.zhihu.com/question/24086463/answer/64717159)。
publicvoidtrimToSize(){
modCount++;
//如果size小于length
if(size<elementData.length){
//重新將elementData設置大小為size
elementData=(size==0)
?EMPTY_ELEMENTDATA
:Arrays.copyOf(elementData,size);
}
}
2.size()
說明:返回ArrayList的大小
源碼解釋:直接返回size
publicintsize(){
returnsize;
}
3.isEmpty()
說明:返回是否為空
**源碼解釋:**直接返回判斷size==0
publicbooleanisEmpty(){
returnsize==0;
}
4.indexOf(Objecto)
說明:對象o在ArrayList中的下標位置,如果存在返回位置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)
說明:是否包含對象o
源碼解釋:調(diào)用indexOf()方法得到下標,存在則下標>=0,不存在為-1,即只要比較下標和0的大小即可。
publicbooleancontains(Objecto){
returnindexOf(o)>=0;
}
6.lastIndexOf(Objecto)
說明:返回容器內(nèi)出現(xiàn)o的最后一個位置
源碼解釋:從后向前遍歷,得到第一個出現(xiàn)對象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()
說明:返回此ArrayList實例的淺表副本。
源碼解釋:
publicObjectclone(){
try{
//調(diào)用父類(翻看源碼可見是Object類)的clone方法得到一個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()
說明:ArrayList實例轉換為。
源碼解釋:直接調(diào)用Arrays類的copyOf。
publicObject[]toArray(){
returnArrays.copyOf(elementData,size);
}
9.toArray(T[]a)
說明:將ArrayList里面的元素賦值到一個數(shù)組中去
源碼解釋:如果a的長度小于ArrayList的長度,直接調(diào)用Arrays類的copyOf,返回一個比a數(shù)組長度要大的新數(shù)組,里面元素就是ArrayList里面的元素;如果a的長度比ArrayList的長度大,那么就調(diào)用System.arraycopy,將ArrayList的elementData數(shù)組賦值到a數(shù)組,然后把a數(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)
說明:測試index是否越界
源碼解釋:
privatevoidrangeCheck(intindex){
//如果下標超過ArrayList的數(shù)組長度
if(index>=size)
//拋出IndexOutOfBoundsException異常
thrownewIndexOutOfBoundsException(outOfBoundsMsg(index));
}
11.get(intindex)
說明:獲取index位置的元素
源碼解釋:先檢查是否越界,然后返回ArrayList的elementData數(shù)組index位置的元素。
publicEget(intindex){
//檢查是否越界
rangeCheck(index);
//返回ArrayList的elementData數(shù)組index位置的元素
returnelementData(index);
}
12.set(intindex,Eelement)
說明:設置index位置的元素值了element,返回該位置的之前的值
源碼解釋:
publicEset(intindex,Eelement){
//檢查是否越界
rangeCheck(index);
//調(diào)用elementData(index)獲取到當前位置的值
EoldValue=elementData(index);
//將element賦值到ArrayList的elementData數(shù)組的第index位置
elementData[index]=element;
returnoldValue;
}
13.ensureCapacityInternal(intminCapacity)
說明:得到最小擴容量
源碼解釋:
privatevoidensureCapacityInternal(intminCapacity){
if(elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA){
//獲取默認的容量和傳入?yún)?shù)的較大值
minCapacity=Math.max(DEFAULT_CAPACITY,minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
14.ensureExplicitCapacity(intminCapacity)
說明:判斷是否需要擴容
源碼解釋:
privatevoidensureExplicitCapacity(intminCapacity){
modCount++;
//如果最小需要空間比elementData的內(nèi)存空間要大,則需要擴容
if(minCapacity-elementData.length>0)
grow(minCapacity);
}
15.grow()方法
說明:幫助ArrayList動態(tài)擴容的核心方法
源碼解釋:
//MAX_VALUE為231-1,MAX_ARRAY_SIZE就是獲取Java中int的最大限制,以防止越界
privatestaticfinalintMAX_ARRAY_SIZE=Integer.MAX_VALUE-8;
privatevoidgrow(intminCapacity){
//獲取到ArrayList中elementData數(shù)組的內(nèi)存空間長度
intoldCapacity=elementData.length;
//擴容至原來的1.5倍
intnewCapacity=oldCapacity+(oldCapacity>>1);
//再判斷一下新數(shù)組的容量夠不夠,夠了就直接使用這個長度創(chuàng)建新數(shù)組,
//不夠就將數(shù)組長度設置為需要的長度
if(newCapacity-minCapacity<0)
newCapacity=minCapacity;
//判斷有沒超過最大限制
if(newCapacity-MAX_ARRAY_SIZE>0)
newCapacity=hugeCapacity(minCapacity);
//調(diào)用Arrays.copyOf方法將elementData數(shù)組指向新的內(nèi)存空間時newCapacity的連續(xù)空間
//并將elementData的數(shù)據(jù)復制到新的內(nèi)存空間
elementData=Arrays.copyOf(elementData,newCapacity);
}
16.add(Ee)
說明:添加元素e
源碼解釋:
publicbooleanadd(Ee){
//擴容
ensureCapacityInternal(size+1);
//將e賦值給elementData的size+1的位置。
elementData[size++]=e;
returntrue;
}
17.add(intindex,Eelement)
說明:在ArrayList的index位置,添加元素element
源碼解釋:
publicvoidadd(intindex,Eelement){
//判斷index是否越界
rangeCheckForAdd(index);
//擴容
ensureCapacityInternal(size+1);
//將elementData從index位置開始,復制到elementData的index+1開始的連續(xù)空間
System.arraycopy(elementData,index,elementData,index+1,
size-index);
//在elementData的index位置賦值element
elementData[index]=element;
//ArrayList的大小加一
size++;
}
18.remove(intindex)
說明:在ArrayList的移除index位置的元素
源碼解釋:
publicEremove(intindex){
//判斷是否越界
rangeCheck(index);
modCount++;
//讀取舊值
EoldValue=elementData(index);
//獲取index位置開始到最后一個位置的個數(shù)
intnumMoved=size-index-1;
if(numMoved>0)
//將elementData數(shù)組index+1位置開始拷貝到elementData從index開始的空間
System.arraycopy(elementData,index+1,elementData,index,
numMoved);
//使size-1,設置elementData的size位置為空,讓GC來清理內(nèi)存空間
elementData[--size]=null;//cleartoletGCdoitswork
returnoldValue;
}
19.remove(Objecto)
說明:在ArrayList的移除對象為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()
說明:設置全部元素為null值,并設置size為0。
源碼解釋:可見clear操作并不是從空間內(nèi)刪除,只是設置為null值,等待垃圾回收機制來回收而已,把size設置為0,以便我們不會瀏覽到null值的內(nèi)存空間。
publicvoidclear(){
modCount++;
//cleartoletGCdoitswork
for(inti=0;i<size;i++)
elementData[i]=null;
size=0;
}
21.addAll(Collectionc)
說明:將Collectionc的全部元素添加到ArrayList中
源碼解釋:
publicbooleanaddAll(Collectionc){
//將c轉換為數(shù)組a
Object[]a=c.toArray();
//獲取a占的內(nèi)存空間長度賦值給numNew
intnumNew=a.length;
//擴容至size+numNew
ensureCapacityInternal(size+numNew);//IncrementsmodCount
//將a的第0位開始拷貝至elementData的size位開始,拷貝長度為numNew
System.arraycopy(a,0,elementData,size,numNew);
//將size增加numNew
size+=numNew;
//如果c為空,返回false,c不為空,返回true
returnnumNew!=0;
}
22.addAll(intindex,Collectionc)
說明:從第index位開始,將c全部拷貝到ArrayList
源碼解釋:
publicbooleanaddAll(intindex,Collectionc){
//判斷index大于size或者是小于0,如果是,則拋出IndexOutOfBoundsException異常
rangeCheckForAdd(index);
//將c轉換為數(shù)組a
Object[]a=c.toArray();
intnumNew=a.length;
//擴容至size+numNew
ensureCapacityInternal(size+numNew);//IncrementsmodCount
//獲取需要添加的個數(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)
說明:根據(jù)complement值,將ArrayList中包含c中元素的元素刪除或者保留
源碼解釋:
privatebooleanbatchRemove(Collectionc,booleancomplement){
finalObject[]elementData=this.elementData;
//定義一個w,一個r,兩個同時右移
intr=0,w=0;
booleanmodified=false;
try{
//r先右移
for(;r<size;r++)
//如果c中不包含elementData[r]這個元素
if(c.contains(elementData[r])==complement)
//則直接將r位置的元素賦值給w位置的元素,w自增
elementData[w++]=elementData[r];
}finally{
//防止拋出異常導致上面r的右移過程沒完成
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)
說明:ArrayList移除c中的所有元素
源碼解釋:
publicbooleanremoveAll(Collectionc){
//如果c為空,則拋出空指針異常
Objects.requireNonNull(c);
//調(diào)用batchRemove移除c中的元素
returnbatchRemove(c,false);
}
26.retainAll(Collectionc)
說明:和removeAll相反,僅保留c中所有的元素
源碼解釋:
publicbooleanretainAll(Collectionc){
Objects.requireNonNull(c);
//調(diào)用batchRemove保留c中的元素
returnbatchRemove(c,true);
}
27.iterator()
說明:返回一個Iterator對象,Itr為ArrayList的一個內(nèi)部類,其實現(xiàn)了Iterator接口
publicIteratoriterator(){
returnnewItr();
}
28.listIterator()
說明:返回一個ListIterator對象,ListItr為ArrayList的一個內(nèi)部類,其實現(xiàn)了ListIterator接口
源碼解釋:
publicListIteratorlistIterator(){
returnnewListItr(0);
}
29.listIterator(intindex)
說明:返回一個從index開始的ListIterator對象
源碼解釋:
publicListIteratorlistIterator(intindex){
if(index<0||index>size)
thrownewIndexOutOfBoundsException("Index:"+index);
returnnewListItr(index);
}
30.subList(intfromIndex,inttoIndex)
說明:根據(jù)兩個參數(shù),獲取到一個子序列
源碼解釋:
publicListsubList(intfromIndex,inttoIndex){
//檢查異常
subListRangeCheck(fromIndex,toIndex,size);
//調(diào)用SubList類的構造方法
returnnewSubList(this,0,fromIndex,toIndex);
}
五、內(nèi)部類
(1)privateclassItrimplementsIterator
(2)privateclassListItrextendsItrimplementsListIterator
(3)privateclassSubListextendsAbstractListimplementsRandomAccess
(4)staticfinalclassArrayListSpliteratorimplementsSpliterator
ArrayList有四個內(nèi)部類,
其中的Itr是實現(xiàn)了Iterator接口,同時重寫了里面的hasNext(),next(),remove()等方法;
其中的ListItr繼承Itr,實現(xiàn)了ListIterator接口,同時重寫了hasPrevious(),nextIndex(),
previousIndex(),previous(),set(Ee),add(Ee)等方法,所以這也可以看出了Iterator和ListIterator的區(qū)別,就是ListIterator在Iterator的基礎上增加了添加對象,修改對象,逆向遍歷等方法,這些是Iterator不能實現(xiàn)的。具體可以參考http://blog.csdn.net/a597926661/article/details/7679765。
其中的SubList繼承AbstractList,實現(xiàn)了RandmAccess接口,類內(nèi)部實現(xiàn)了對子序列的增刪改查等方法,但它同時也充分利用了內(nèi)部類的優(yōu)點,就是共享ArrayList的全局變量,例如檢查器變量modCount,數(shù)組elementData等,所以SubList進行的增刪改查操作都是對ArrayList的數(shù)組進行的,并沒有創(chuàng)建新的數(shù)組。
以上就是關于Java培訓之容器類ArrayList源碼分析的詳細介紹,最后想要了解更多關于JavaEE開發(fā)問題的小伙伴可以登錄扣丁學堂官網(wǎng)咨詢??鄱W堂是專業(yè)的JavaEE培訓機構,不僅有專業(yè)的老師和與時俱進的課程體系,還有大量的Java視頻教程供學員觀看學習,想要學好JavaEE的小伙伴抓緊時間行動吧。Java技術交流群:670348138。
【關注微信公眾號獲取更多學習資料】
查看更多關于“Java開發(fā)資訊”的相關文章>>
標簽:
Java培訓
Java開發(fā)程序員
Java視頻教程