一点一点看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。

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

 

 

以上!