一点一点看JDK源码(四)java.util.ArrayList 中篇
?一點一點看JDK源碼(四)java.util.ArrayList 中篇
?
liuyuhang原創,未經允許禁止轉載
本文舉例使用的是JDK8的API
?
目錄:一點一點看JDK源碼(〇)
1.綜述
?
在前篇中,對于java.util.ArrayList進行了一些源碼注釋,能堅持看完的估計都是神一般的存在。
不過看源碼并需要一個艱苦的過程,枯燥是很正常的。
但是不是要一直都很枯燥,本文將對此類進行分類解析。
?
2.關注點
2.0.ArrayList是如何構成的?
在java中,一個類的構成并不是十分復雜,列舉出來,一頁紙應該是足夠的,我嘗試下。
2.0.1.類的定義
類的定義中,會聲明是class,AbstractClass,或者interface。
該類是否含有該類沒有顯示定義的方法,取決于向上有多少個extends的父類的存在。
該類是否有必須實現的方法,取決于向上有多少個implments的接口的存在。
?
2.0.2.類的構造
無參構造器,帶參構造器。
?
構造器的方法名是和類名同名的,并且沒有返回值。
構造器不管是無參的,還是帶參的,不管使用何種方式調用,
都說明該類已經被實例化了。
構造器內也可以寫很多奇葩的代碼的,當然也許是常用手段。
在構造器內寫代碼以實現自己想實現的功能,相當于一些容器的init,實際上就是初始化。
?
2.0.3.類的成員變量
類的成員變量,不管如何定義,都是為該類內使用該變量提供一定的便利性
類的成員變量,理論上就是該類內的全局變量,如果是public,或者default,protected,
都是一種對該全局變量的開放性。
成員變量,可以是static的(靜態,類加載即加載),可以是final的(只允許實例化一次)
?
2.0.4.類的成員方法
類的成員方法,在不論其使用范圍的情況下,都是一種方法,根據實例化使用的構造不同,
可調用的方法范圍不同。
若使用父類構造器來接收子類實例(如:Object obj = new ArrayList()),
會發現obj可使用的方法就變得很少了(只有Object的方法允許使用了)。如下圖:
(Object是java中所有類的基類,沒有顯示繼承也是被繼承的)
因此,即使List list = new ArrayList();
用起來,字數更少,寫起來更方便,但是失去了一些功能。
當然,簡單的使用List接口來操作ArrayList實例化對象也是能滿足一定要求的,
也并非不可以使用。
?
2.0.5.類的內部類
?
ArrayList也有一些內部類,內部類使用成員方法進行實例化,返回的是其Implments接口的對象。
由于其接口的方法在內部類中被復寫,所以直接調用接口的方法,實際上是調用其內部類的方法。
關于內部類,下文中有列舉。
?
2.0.6.類的實例化
類的成員方法,隨著實例化時接收的對象類型不同而不同,因為我們只能調用對象所在類提供
的方法,所以了解ArrayList實例化后的特性,就應該使用ArrayList類來接收實例化對象。
(上文已有,不再贅述)
2.1.ArrayList提供了什么?
?
提供了什么?我也并非十分清楚。在第一篇中,我認為Collection下都是容器,因此作為一個容器,
應該提供容器應該有的特性吧,比如:
容器存儲結構(底層存儲結構)
容積計算(定容和擴容)
增刪改查方法
特性方法(取決于儲存結構和要實現的特性)
?
實際上這個內容還是能夠進行一些分類的。ArrayList提供了如下具體內容:
2.1.1.常量和成員變量(無法直接訪問,允許調用public方法訪問)
常量包括容量(size,MAX。。),底層存儲結構(Object數組),序列化版本,默認儲存等。
?
2.1.2.構造器和初始化(可調用構造器)
?
clinit是該類在VM裝載的時候初始化用的,暫不深究。
它提供了三個構造器:
一個無參構造器ArrayList();
兩個帶參構造器ArrayList(int)和ArrayList(Collection< ? extends E>)
?
初學的時候總有一種迷惑的感覺,構造器無非就是實例化的,為什么要提供好幾個構造器?
這三個構造器都應該在什么時候使用呢?
如果不確定你定義這個容器的時候,容量多大,容器內容是什么,那么應該使用無參構造器。
?
如果確定你定義這個構造器的容量,或者至少容量會有多少,可以使用ArrayList(int)構造。
因為在ArrayList底層是Object數組,數組的容量是確定的,因此每次增加內容都需要對數組
進行擴容,擴容過程中要用新數組接收拷貝后的舊數組,所以節約計算資源效率,在能確定
容量的情況下,最好使用定容構造器ArrayList(int)。
?
如果一個容器內將直接增加數據,那么該數據最好是來自集合,也就是說向上兩層的接口
Collection之下的所有結構,都可以直接轉化為ArrayList的,此時就應該選擇使用
ArrayList(Collection< ? extends E>)構造器了。
ArrayList查詢快,增刪慢,這個是官方說法。快慢實際上是相對而言的,相對于誰呢?
一般說到數組的相對性,都指的是鏈表。
即,接收參數的時候,使用鏈表,查詢和加工參數的時候,使用數組。
?
2.1.3.成員方法
ArrayList提供的成員方法很多,主要分為三類:
1.增刪改查對容器直接操作,歸為一類。
2.內部保護方法,內部處理數據中調用的方法,或只暴露給uitl包的方法,無法公開調用。
3.其余的,對于容器特性的操作,或數據轉化的操作,歸為一類。
?
增:add,addAll,分別對應添加單個元素和添加多個元素,其中有對于index的指定參數時,
就是針對指定index后插入實參對象。位指定的時候默認加在末尾。
add和addAll的時候有進行擴容判斷,擴容倍數為1.5倍。(先擴容,增加后再去掉空元素)
?
刪:remove,removeAll,removeIf,分別對應刪除單個元素,刪除多個元素,按條件匹配刪除。
傳入參數有指定的index(按指定index刪除),雙index(按指定index范圍刪除),
Object(嘗試找到此元素并刪除,返回操作標識),Collection(刪除指定集合內容)
Predicate接口(作為filter來進行是否刪除的過濾,功能類似于Compare接口)。
有些刪除的方法是帶有返回值的,為boolean,或被刪除的內容,應當接收,作為是否成功,
或者操作可能需要回滾的判斷。
?
改:set,改指定index的值為實參對象。
?
查:get,根據index獲取元素。indexOf,lastIndexOf,分別正序或倒敘根據元素查index
內部保護方法:
一點點去找內部保護方法去看定義,比較麻煩,可以直接看結構。
若該方法有紅色方框標記,就是不對外公開調用的了。如下圖:
內部保護方法,之所以不對外公開,是因為外部調用的時候,因為考慮不周,或調用方式錯誤,
或者其他原因吧,將導致有錯誤出現,本身可能也并非是一個完整的操作鏈,所以保護起來。
?
如fastRemove(int)方法,util包下都可以調用,有和remove有區別在于,它省略掉了index校驗
還有rangeCheck(int),是專門用于index校驗的方法,也沒有必要對外公開,它屬于
其他方法,如add,addAll的一部分,這種方法抽取出來的原因,多數因為出現次數超過三次,
因此就有必要進行重新封裝了。
?
特性操作:
特性操作細分下來,也可以按照功能進行細分。如:
清空(clear),克隆(clone),容量(size),判空(isEmpty),判斷包含(cantains),
容量優化(ensureCapacity),遍歷(forEach),迭代器(iterator等),拆分(subList),
拆分迭代(spliterator),比較排序(sort),轉數組(toArray),替換(replace),
去空(trimToSize),求交集(retainAll)
其中,清空,替換,排序,容量優化,都是對ArrayList自身的操作。
克隆,容量,判斷,都是對ArrayList的一種特性或內容查詢方式。
而遍歷,迭代,拆分,迭代拆分,就純粹是數據加工,而獲得其他對象了。
其中拆分,迭代拆分,Collection接口下的Stream(聚合)都是1.8新增的了。
?
2.1.4.成員方法調用的內部類
ArrayList中一共有四個內部類,都是要用成員方法來調用的。內部類如下圖:
分別是ArrayListSpliterator,Itr,ListItr,SubList。調用的方法分別如下:
?
具體用法,下篇再研究吧我!!
?
3.其他關注點
?
發現了一些奇葩關注點,不知道有用沒,說下而已。
?
內部類的類名展示是使用$做連接符的,mybatis中的mapper.xml要使用內部類來接收的話,該內部類必須是靜態的。
貌似VM在編譯的時候是拆分編譯的,但是命名不是,還是按照內部處理的,如下圖:
?
成員變量elementData前有關鍵字transient進行修飾,表示該變量不參與實例化,應該是作為緩存的意思了。
fastRemove不僅本類可用,util包下其他的類也可以調用還。
?
要使用Collection下的Stream(聚合)方法的話,必須要將ArrayList用Collection來做對象的類型來接收,然后才可以使用。
?
ArrayList是線程不安全的,那么modCount真的那么有用么,就不理解了,不會只用在序列化上吧。也沒見到有回滾方法。
?
官方介紹中,ArrayList在List接口下,List接口下的實例定義為隨機存取不支持,感覺應該寫的出來吧,只是壓根沒寫。隨
機存有影響,隨機取還不容易咩?沒誰會考慮自己繼承ArrayList然后重新擴展吧,估計也有可能,我沒見過而已。
?
ArrayList中對Arrays工具類,和System類都有應用。
?
retainAll調用了內部方法batchRemove,作為一個交集判斷操作,使用了緩沖區elementData。
如果要提供取交集操作該多好!!
?
?
以上!
?
轉載于:https://www.cnblogs.com/liuyuhangCastle/p/9643671.html
總結
以上是生活随笔為你收集整理的一点一点看JDK源码(四)java.util.ArrayList 中篇的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 成为一名优秀的程序员基本要素
- 下一篇: js setTimeout 传递带参数的