一點一點看JDK源碼(四)java.util.ArrayList 中篇

 一點一點看JDK源碼(四)java.util.ArrayList 中篇html

 

liuyuhang原創,未經容許禁止轉載java

本文舉例使用的是JDK8的API數組

 

目錄:一點一點看JDK源碼(〇)

1.綜述緩存

 

  在前篇中,對於java.util.ArrayList進行了一些源碼註釋,能堅持看完的估計都是神通常的存在。安全

  不過看源碼並須要一個艱苦的過程,枯燥是很正常的。mybatis

  可是不是要一直都很枯燥,本文將對此類進行分類解析。app

 

2.關注點工具

  2.0.ArrayList是如何構成的?post

    在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。

      若是要提供取交集操做該多好!!

 

 

以上!

相關文章
相關標籤/搜索