第九篇、java中ArrayList源碼解析

    引言

如題,爲什麼今天要給大家介紹java的中的ArrayList的源碼呢?因爲我畢竟是一個android開發工程師,不能一直給大家通過c語言講解數據結構呀,java中也存在數據結構知識呢,我們的第7篇文章中介紹了下線性表中的順序表,今天我們就來介紹一下java中的“順序表的應用”,即ArrayList。

那大家大概猜到了,既然我說ArrayList是順序表在Java中的應用,那麼他內部是不是通過數組實現的呢?
你猜對了,就是通過數組實現的。

大致看下源碼

我們來大致看下ArrayList的源碼,這裏我是通過Android studio看的,所以源碼應該和java工程師用eclipse看的不太一樣(有一些常量值可能不太一樣),但是大體邏輯是類似的。
我貼張圖,大家來感受一下:

 

Arraylist源碼.png

Arraylist源碼.png

我們看到,Arraylist源碼有1476行,感覺是比較複雜的,而我們感興趣的無非就是那麼幾種:

創建

添加元素

刪除元素

清空列表

轉成數組

所以,本篇文章就先從這幾點入手,如果後續有朋友需要對其他操作解析講解的話,可以私信我,我會再幫你分析一下的。

ArrayList的創建

先來看圖

 

ArrayList創建.png

ArrayList創建.png


ArrayList創建提供了三個構造方法:

  • 帶int 參數的構造方法
  • 無參構造方法
  • 帶集合參數的構造方法
    我們先來看第一個

1、帶int 參數的構造方法

 

帶int參數的構造方法.png

帶int參數的構造方法.png


其實大家看上方的英文註釋就能明白一二了:
“這個構造方法指定了一個固定的容量,使用參數去設置Arraylist的容量大小”
所以說我們就可以這樣去創建ArrayList:
ArrayList<String> list=new ArrayList<String>(5);
通過指定固定的大小去創建ArrayList。

但是,這樣做就能夠真的讓ArrayList的容量是5了嗎?我們來分析下

 

構造方法1.png

構造方法1.png


需要參考的值

 

構造方法1值.png

構造方法1值.png


細看源碼,是不是恍然大悟,原來集合內部有一個“內部數組"
elementData

看我們的註釋,我們似乎猜對了,只要我們傳入的容量值大於0,就能夠設定固定容量的集合,如果傳入的等於0,就直接用的是一個空的數組,如果小於0,則直接報錯。


2、無參的構造方法

我們看過了有參的構造方法,其實再看無參的構造方法就覺得簡單多了,來看一下吧:

 

構造方法2.png

構造方法2.png


需要參考的值

 

構造方法2值.png

構造方法2值.png


”即複用了一個空的數組,這個數組和方法一種的數組是區分開的,區分開的目的是在進行第一個元素添加的時候計算需要擴充多大的容量。“
ok,其實我們常用的也就這樣,直接new 出來
ArrayList<String> list=new ArrayList<String>();
所以我們這樣寫,跟我們直接指定大小容量的寫現在看看應該沒什麼區別。
 


3、帶collection參數的構造方法

 

構造方法三.png

構造方法三.png


"參數是一個帶泛型的集合,該構造方法將會把參數中的元素放置到新創建的集合中去"
即通過這個方法我們可以獲得跟傳入集合一樣的集合,裏面的元素都是一模一樣的,就是創建了個副本
解釋一下

構造方法二解析.png

構造方法二解析.png


我們使用的時候就可以這樣

構造方法3使用.png

構造方法3使用.png


得到list1的副本~~


ok,ArrayList的創建就先到這裏,接下來我們看看ArrayList元素的添加

添加元素

兩個.png

兩個.png


元素添加有兩個方法,我們先看第一個

1、添加元素到結尾方法

元素添加1.png

元素添加1.png


”將元素添加到集合的最後位置“
解釋一下

添加元素解釋.png

添加元素解釋.png


我們看到,首先在添加元素的時候,做了一個擴容的操作我們點擊進去看一下

擴容.png

擴容.png


我們看一下參考值

擴容參考值.png

擴容參考值.png


接着,在擴容方法中又調用了一個”明確擴容的方法“:

明確擴容.png

明確擴容.png


緊接着,又調用了下grow方法,到這裏grow纔是真正的擴容方法了

 

真正的擴容方法.png

真正的擴容方法.png


在擴容方法的最後,我們看到了數組複製的邏輯:

 

數組複製.png

數組複製.png


但是我們接着點進去,看看真正的數組複製的方法

複製數組方法2.png

複製數組方法2.png


在進入System.arraycopy方法

 

真正數組複製的方法.png

真正數組複製的方法.png


因爲add方法套的比較深了一點點,所以我畫了張圖,來看一下

 

java add流程.png

java add流程.png


應該對你理解有點幫助吧~~

最終

 

把要插入元素添加到結尾.png

把要插入元素添加到結尾.png


2、添加元素到指定位置

 

添加元素到指定位置.png

添加元素到指定位置.png


“把指定元素添加到集合的指定位置(將要插入元素位置之後的元素向後移動一個單位,然後將元素插入到中間)”
解釋一下

插入元素到指定位置.png

插入元素到指定位置.png


我們看到,
1、首先做了一個參數校驗,不允許插入索引大於集合的容量或者小於零,否則報數組越界異常。
2、跟上方的add(E element)方法一致,做擴容和複製的操作
3、這一點和add(E element)方法不一致,且比較關鍵,他的作用是將要插入元素位置之後的元素向後移動一個單位
4、在要插入的位置替換成要插入元素的值
5、增加集合長度
 


刪除元素

刪除元素兩種.png

刪除元素兩種.png


即一個是根據索引刪除,一個是根據元素值刪除
我們先來看根據索引刪除的

1、根據索引刪除元素

我們先看圖

刪除元素01.png

刪除元素01.png


“將指定位置的元素刪除,並且把刪除位置後邊的元素向左移動”
解釋一下:

根據索引刪除元素解釋.png

根據索引刪除元素解釋.png


比添加元素簡單,因爲不需要考慮到擴容問題
接着看

 

2、根據元素值刪除元素

看源碼:

 

根據元素值刪除元素.png

根據元素值刪除元素.png


“將第一次出現的對應元素值的元素刪除掉,如果集合中沒有這個元素值,集合將不會有所改變”
解釋一下啦

根據元素值刪除解釋.png

根據元素值刪除解釋.png


我們看到上邊有一個fastRemove方法,我們來看一下:

fastremove.png

fastremove.png


我們看到,這個fastRemove方法和我們的根據索引刪除方法很像
1、modCount++是計數單位,我們不做考慮
2、int numMoved=size-index-1;計算要移動的元素數量
3、移動元素
4、將結尾元素置爲空。
所以其實根據元素值刪除元素也是依據根據索引刪除的。

清空集合

就是我們常用的clear方法,我們來看一下

清空集合.png

清空集合.png


"移除集合中的所有元素,當處理結束後,這個集合就是一個空集合"
我們看步驟:
1、modCount++不需要考慮,跳過
2、循環數組,將每個元素置爲空
3、改變集合長度爲0
so easy!

 

轉爲數組

即我們常用的toArray方法

 

toarray.png

toarray.png


我們看到,有兩個方法,一個無參,一個有參

1、無參toArray方法

 

無參toArray.png

無參toArray.png


“根據集合的順序,返回一個包含所有元素的集合”
我們看到上邊ArrayCopy應該就能想到上方我們添加元素那的操作了吧。操作是一致的,就是將集合中的數組的所有元素都複製到另外一個數組中,並且返回。
點進去看看:

toarray進入1.png

toarray進入1.png


toarray進入2.png

toarray進入2.png


就是將原來集合中的數組再進行了一次複製

 

2、有參toArray方法

有參toArray.png

有參toArray.png


"根據集合的順序,返回一個包含所有元素的集合,這個集合是自己指定的,如果指定的這個集合有足夠的空間,那麼如果將所有元素複製進來的話,源集合尾元素將置爲空"
解釋一下:

有參toArray解釋.png

有參toArray解釋.png


總結,好了,今天介紹了也不少了,但是還有查找,替換這兩個簡單的操作還沒有講解到,不過看完今天的介紹,這兩個操作對大家來說應該沒什麼問題了。不過有問題也可以私信我~~

謝謝大家關注~~~麼麼噠

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章