zoukankan      html  css  js  c++  java
  • java集合框架03——ArrayList和源码分析

        最近忙着替公司招人好久没写了,荒废了不好意思。

       上一章学习了Collection的架构,并阅读了部分源码,这一章开始,我们将对Collection的具体实现进行详细学习。首先学习List。而ArrayList又是List中最为常用的,因此本章先学习ArrayList。先对ArrayList有个整体的认识,然后学习它的源码,深入剖析ArrayList。

    1. ArrayList简介

        首先看看ArrayList与Collection的关系:

        ArrayList的继承关系如下:

    java.lang.Object  
       ↳     java.util.AbstractCollection<E>  
             ↳     java.util.AbstractList<E>  
                   ↳     java.util.ArrayList<E>  
      
    public class ArrayList<E> extends AbstractList<E>  
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable {}  

       ArrayList继承了AbstractList,实现了List。它是一个数组队列,相当于动态数组。提供了相关的添加、删除、修改和遍历等功能。

        ArrayList实现了RandomAccess接口,即提供了随机访问功能。RandomAccess是Java中用来被List实现,为List提供快速访问功能的。在ArrayList中,我们即可以通过元素的序号来快速获取元素对象,这就是快速随机访问。下文会比较List的“快速随机访问”和使用“Iterator迭代器访问”的效率。

        ArrayList实现了Cloneable接口,即覆盖了函数clone(),能被克隆。

        ArrayList实现了java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输。

        和Vector不同,ArrayList中的操作是非线程安全的。所以建议在单线程中使用ArrayList,在多线程中选择Vector或者CopyOnWriteArrayList。

        我们先总览下ArrayList的构造函数和API

    /****************** ArrayList中的构造函数 ***************/  
    // 默认构造函数  
    ArrayList()  
      
    // capacity是ArrayList的默认容量大小。当由于增加数据导致容量不足时,容量会添加上一次容量大小的一半。  
    ArrayList(int capacity)  
      
    // 创建一个包含collection的ArrayList  
    ArrayList(Collection<? extends E> collection)  
      
    /****************** ArrayList中的API ********************/  
    // Collection中定义的API  
    boolean             add(E object)  
    boolean             addAll(Collection<? extends E> collection)  
    void                clear()  
    boolean             contains(Object object)  
    boolean             containsAll(Collection<?> collection)  
    boolean             equals(Object object)  
    int                 hashCode()  
    boolean             isEmpty()  
    Iterator<E>         iterator()  
    boolean             remove(Object object)  
    boolean             removeAll(Collection<?> collection)  
    boolean             retainAll(Collection<?> collection)  
    int                 size()  
    <T> T[]             toArray(T[] array)  
    Object[]            toArray()  
    // AbstractCollection中定义的API  
    void                add(int location, E object)  
    boolean             addAll(int location, Collection<? extends E> collection)  
    E                   get(int location)  
    int                 indexOf(Object object)  
    int                 lastIndexOf(Object object)  
    ListIterator<E>     listIterator(int location)  
    ListIterator<E>     listIterator()  
    E                   remove(int location)  
    E                   set(int location, E object)  
    List<E>             subList(int start, int end)  
    // ArrayList新增的API  
    Object               clone()  
    void                 ensureCapacity(int minimumCapacity)  
    void                 trimToSize()  
    void                 removeRange(int fromIndex, int toIndex) 

     ArrayList包含了两个重要的对象:elementData和size。

        elementData是Object[]类型的数组,它保存了添加到ArrayList中的元素。实际上,elementData是一个动态数组,我们能通过ArrayList(int initialCapacity)来执行它的初始容量为initialCapacity。如果通过不含参数的构造函数来创建ArrayList,则elementData是一个空数组(后面会调整其大小)。elementData数组的大小会根据ArrayList容量的增长而动态的增长,具体见下面的源码。

       size则是动态数组实际的大小。

    2. ArrayList源码分析(基于JDK1.7)

            下面通过分析ArrayList的源码更加深入的了解ArrayList原理。由于ArrayList是通过数组实现的,所以源码比较容易理解:

            篇幅有点长请一定要耐心看,有点心理准备

      1 package java.util;  
      2   
      3 public class ArrayList<E> extends AbstractList<E>  
      4         implements List<E>, RandomAccess, Cloneable, java.io.Serializable  
      5 {  
      6     //序列版本号  
      7     private static final long serialVersionUID = 8683452581122892189L;  
      8   
      9     //默认初始化容量  
     10     private static final int DEFAULT_CAPACITY = 10;  
     11   
     12     //空数组,用来实例化不带容量大小的构造函数  
     13     private static final Object[] EMPTY_ELEMENTDATA = {};  
     14   
     15     //保存ArrayList中数据的数组  
     16     private transient Object[] elementData;  
     17   
     18     //ArrayList中实际数据的数量  
     19     private int size;  
     20   
     21 /******************************** Constructor ***********************************/  
     22   
     23     //ArrayList带容量大小的构造函数  
     24     public ArrayList(int initialCapacity) {  
     25         super();  
     26         if (initialCapacity < 0)  
     27             throw new IllegalArgumentException("Illegal Capacity: "+  
     28                                                initialCapacity);  
     29         this.elementData = new Object[initialCapacity]; //新建一个数组初始化elementData  
     30     }  
     31     
     32     //不带参数的构造函数  
     33     public ArrayList() {  
     34         super();  
     35         this.elementData = EMPTY_ELEMENTDATA;//使用空数组初始化elementData  
     36     }  
     37   
     38     //用Collection来初始化ArrayList  
     39     public ArrayList(Collection<? extends E> c) {  
     40         elementData = c.toArray(); //将Collection中的内容转换成数组初始化elementData  
     41         size = elementData.length;  
     42         // c.toArray might (incorrectly) not return Object[] (see 6260652)  
     43         if (elementData.getClass() != Object[].class)  
     44             elementData = Arrays.copyOf(elementData, size, Object[].class);  
     45     }  
     46   
     47 /********************************* Array size ************************************/  
     48   
     49     //重新“修剪”数组容量大小  
     50     public void trimToSize() {  
     51         modCount++;  
     52         //当ArrayList中的元素个数小于elementData数组大小时,重新修整elementData到size大小  
     53         if (size < elementData.length) {  
     54             elementData = Arrays.copyOf(elementData, size);  
     55         }  
     56     }  
     57   
     58     //给数组扩容,该方法是提供给外界调用的,是public的,真正扩容是在下面的private方法里  
     59     public void ensureCapacity(int minCapacity) {  
     60         int minExpand = (elementData != EMPTY_ELEMENTDATA)  
     61             // any size if real element table  
     62             ? 0  
     63             // larger than default for empty table. It's already supposed to be  
     64             // at default size.  
     65             : DEFAULT_CAPACITY;  
     66   
     67         if (minCapacity > minExpand) {  
     68             ensureExplicitCapacity(minCapacity);  
     69         }  
     70     }  
     71   
     72     private void ensureCapacityInternal(int minCapacity) {  
     73     //如果是个空数组  
     74         if (elementData == EMPTY_ELEMENTDATA) {  
     75         //取minCapacity和10的较大者  
     76             minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);  
     77         }  
     78     //如果数组已经有数据了  
     79         ensureExplicitCapacity(minCapacity);  
     80     }  
     81       
     82     //确保数组容量大于ArrayList中元素个数  
     83     private void ensureExplicitCapacity(int minCapacity) {  
     84         modCount++; //将“修改统计数”+1  
     85   
     86         //如果实际数据容量大于数组容量,就给数组扩容  
     87         if (minCapacity - elementData.length > 0)  
     88             grow(minCapacity);  
     89     }  
     90   
     91     //分配的最大数组空间  
     92     private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;  
     93   
     94     //增大数组空间  
     95     private void grow(int minCapacity) {  
     96         // overflow-conscious code  
     97         int oldCapacity = elementData.length;  
     98         int newCapacity = oldCapacity + (oldCapacity >> 1); //在原来容量的基础上加上 oldCapacity/2  
     99         if (newCapacity - minCapacity < 0)  
    100             newCapacity = minCapacity; //最少保证容量和minCapacity一样  
    101         if (newCapacity - MAX_ARRAY_SIZE > 0)  
    102             newCapacity = hugeCapacity(minCapacity); //最多不能超过最大容量  
    103         // minCapacity is usually close to size, so this is a win:  
    104         elementData = Arrays.copyOf(elementData, newCapacity);  
    105     }  
    106   
    107     private static int hugeCapacity(int minCapacity) {  
    108         if (minCapacity < 0) // overflow  
    109             throw new OutOfMemoryError();  
    110         return (minCapacity > MAX_ARRAY_SIZE) ?  
    111             Integer.MAX_VALUE :  
    112             MAX_ARRAY_SIZE;  
    113     }  
    114   
    115     //返回ArrayList的实际大小  
    116     public int size() {  
    117         return size;  
    118     }  
    119   
    120     //判断ArrayList是否为空  
    121     public boolean isEmpty() {  
    122         return size == 0;  
    123     }   
    124   
    125 /****************************** Search Operations *************************/  
    126   
    127     //判断ArrayList是否包含Object o  
    128     public boolean contains(Object o) {  
    129         return indexOf(o) >= 0;  
    130     }  
    131   
    132     //正向查找,返回元素的索引值  
    133     public int indexOf(Object o) {  
    134         if (o == null) {  
    135             for (int i = 0; i < size; i++)  
    136                 if (elementData[i]==null)  
    137                     return i;  
    138         } else {  
    139             for (int i = 0; i < size; i++)  
    140                 if (o.equals(elementData[i]))  
    141                     return i;  
    142         }  
    143         return -1;  
    144     }  
    145   
    146     //反向查找,返回元素的索引值  
    147     public int lastIndexOf(Object o) {  
    148         if (o == null) {  
    149             for (int i = size-1; i >= 0; i--)  
    150                 if (elementData[i]==null)  
    151                     return i;  
    152         } else {  
    153             for (int i = size-1; i >= 0; i--)  
    154                 if (o.equals(elementData[i]))  
    155                     return i;  
    156         }  
    157         return -1;  
    158     }  
    159   
    160 /******************************* Clone *********************************/  
    161   
    162     //克隆函数  
    163     public Object clone() {  
    164         try {  
    165             @SuppressWarnings("unchecked")  
    166                 ArrayList<E> v = (ArrayList<E>) super.clone();  
    167         //将当前ArrayList的全部元素拷贝到v中  
    168             v.elementData = Arrays.copyOf(elementData, size);  
    169             v.modCount = 0;  
    170             return v;  
    171         } catch (CloneNotSupportedException e) {  
    172             // this shouldn't happen, since we are Cloneable  
    173             throw new InternalError();  
    174         }  
    175     }  
    176   
    177 /********************************* toArray *****************************/  
    178   
    179     /** 
    180     * 返回一个Object数组,包含ArrayList中所有的元素 
    181     * toArray()方法扮演着array-based和collection-based API之间的桥梁 
    182     */  
    183     public Object[] toArray() {  
    184         return Arrays.copyOf(elementData, size);  
    185     }  
    186   
    187     //返回ArrayList的模板数组  
    188     @SuppressWarnings("unchecked")  
    189     public <T> T[] toArray(T[] a) {  
    190     //如果数组a的大小 < ArrayList的元素个数,  
    191     //则新建一个T[]数组,大小为ArrayList元素个数,并将“ArrayList”全部拷贝到新数组中。  
    192         if (a.length < size)  
    193             return (T[]) Arrays.copyOf(elementData, size, a.getClass());  
    194   
    195     //如果数组a的大小 >= ArrayList的元素个数,  
    196     //则将ArrayList全部拷贝到新数组a中。  
    197         System.arraycopy(elementData, 0, a, 0, size);  
    198         if (a.length > size)  
    199             a[size] = null;  
    200         return a;  
    201     }  
    202   
    203 /******************** Positional Access Operations ********************/  
    204   
    205     @SuppressWarnings("unchecked")  
    206     E elementData(int index) {  
    207         return (E) elementData[index];  
    208     }  
    209   
    210     //获取index位置的元素值  
    211     public E get(int index) {  
    212         rangeCheck(index); //首先判断index的范围是否合法  
    213   
    214         return elementData(index);  
    215     }  
    216   
    217     //将index位置的值设为element,并返回原来的值  
    218     public E set(int index, E element) {  
    219         rangeCheck(index);  
    220   
    221         E oldValue = elementData(index);  
    222         elementData[index] = element;  
    223         return oldValue;  
    224     }  
    225   
    226     //将e添加到ArrayList中  
    227     public boolean add(E e) {  
    228         ensureCapacityInternal(size + 1);  // Increments modCount!!  
    229         elementData[size++] = e;  
    230         return true;  
    231     }  
    232   
    233     //将element添加到ArrayList的指定位置  
    234     public void add(int index, E element) {  
    235         rangeCheckForAdd(index);  
    236   
    237         ensureCapacityInternal(size + 1);  // Increments modCount!!  
    238     //将index以及index之后的数据复制到index+1的位置往后,即从index开始向后挪了一位  
    239         System.arraycopy(elementData, index, elementData, index + 1,  
    240                          size - index);   
    241         elementData[index] = element; //然后在index处插入element  
    242         size++;  
    243     }  
    244   
    245     //删除ArrayList指定位置的元素  
    246     public E remove(int index) {  
    247         rangeCheck(index);  
    248   
    249         modCount++;  
    250         E oldValue = elementData(index);  
    251   
    252         int numMoved = size - index - 1;  
    253         if (numMoved > 0)  
    254         //向左挪一位,index位置原来的数据已经被覆盖了  
    255             System.arraycopy(elementData, index+1, elementData, index,  
    256                              numMoved);  
    257     //多出来的最后一位删掉  
    258         elementData[--size] = null; // clear to let GC do its work  
    259   
    260         return oldValue;  
    261     }  
    262   
    263     //删除ArrayList中指定的元素  
    264     public boolean remove(Object o) {  
    265         if (o == null) {  
    266             for (int index = 0; index < size; index++)  
    267                 if (elementData[index] == null) {  
    268                     fastRemove(index);  
    269                     return true;  
    270                 }  
    271         } else {  
    272             for (int index = 0; index < size; index++)  
    273                 if (o.equals(elementData[index])) {  
    274                     fastRemove(index);  
    275                     return true;  
    276                 }  
    277         }  
    278         return false;  
    279     }  
    280   
    281     //private的快速删除与上面的public普通删除区别在于,没有进行边界判断以及不返回删除值  
    282     private void fastRemove(int index) {  
    283         modCount++;  
    284         int numMoved = size - index - 1;  
    285         if (numMoved > 0)  
    286             System.arraycopy(elementData, index+1, elementData, index,  
    287                              numMoved);  
    288         elementData[--size] = null; // clear to let GC do its work  
    289     }  
    290   
    291     //清空ArrayList,将全部元素置为null  
    292     public void clear() {  
    293         modCount++;  
    294   
    295         // clear to let GC do its work  
    296         for (int i = 0; i < size; i++)  
    297             elementData[i] = null;  
    298   
    299         size = 0;  
    300     }  
    301   
    302     //将集合C中所有的元素添加到ArrayList中  
    303     public boolean addAll(Collection<? extends E> c) {  
    304         Object[] a = c.toArray();  
    305         int numNew = a.length;  
    306         ensureCapacityInternal(size + numNew);  // Increments modCount  
    307     //在原来数组的后面添加c中所有的元素  
    308         System.arraycopy(a, 0, elementData, size, numNew);  
    309         size += numNew;  
    310         return numNew != 0;  
    311     }  
    312   
    313     //从index位置开始,将集合C中所欲的元素添加到ArrayList中  
    314     public boolean addAll(int index, Collection<? extends E> c) {  
    315         rangeCheckForAdd(index);  
    316   
    317         Object[] a = c.toArray();  
    318         int numNew = a.length;  
    319         ensureCapacityInternal(size + numNew);  // Increments modCount  
    320   
    321         int numMoved = size - index;  
    322         if (numMoved > 0)  
    323         //将index开始向后的所有数据,向后移动numNew个位置,给新插入的数据腾出空间  
    324             System.arraycopy(elementData, index, elementData, index + numNew,  
    325                              numMoved);  
    326     //将集合C中的数据插到刚刚腾出的位置  
    327         System.arraycopy(a, 0, elementData, index, numNew);  
    328         size += numNew;  
    329         return numNew != 0;  
    330     }  
    331   
    332     //删除从fromIndex到toIndex之间的数据,不包括toIndex位置的数据  
    333     protected void removeRange(int fromIndex, int toIndex) {  
    334         modCount++;  
    335         int numMoved = size - toIndex;  
    336         System.arraycopy(elementData, toIndex, elementData, fromIndex,  
    337                          numMoved);  
    338   
    339         // clear to let GC do its work  
    340         int newSize = size - (toIndex-fromIndex);  
    341         for (int i = newSize; i < size; i++) {  
    342             elementData[i] = null;  
    343         }  
    344         size = newSize;  
    345     }  
    346       
    347     //范围检测  
    348     private void rangeCheck(int index) {  
    349         if (index >= size)  
    350             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));  
    351     }  
    352   
    353     //add和addAll方法中的范围检测  
    354     private void rangeCheckForAdd(int index) {  
    355         if (index > size || index < 0)  
    356             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));  
    357     }  
    358   
    359     private String outOfBoundsMsg(int index) {  
    360         return "Index: "+index+", Size: "+size;  
    361     }  
    362   
    363     //删除ArrayList中所有集合C中包含的数据  
    364     public boolean removeAll(Collection<?> c) {  
    365         return batchRemove(c, false);  
    366     }  
    367   
    368     //删除ArrayList中除了集合C中包含的数据外的其他所有数据  
    369     public boolean retainAll(Collection<?> c) {  
    370         return batchRemove(c, true);  
    371     }  
    372       
    373     //批量删除  
    374     private boolean batchRemove(Collection<?> c, boolean complement) {  
    375         final Object[] elementData = this.elementData;  
    376         int r = 0, w = 0;  
    377         boolean modified = false;  
    378         try {  
    379             for (; r < size; r++)  
    380                 if (c.contains(elementData[r]) == complement)  
    381                     elementData[w++] = elementData[r];  
    382         } finally {  
    383             // Preserve behavioral compatibility with AbstractCollection,  
    384             // even if c.contains() throws.  
    385         //官方的注释是为了保持和AbstractCollection的兼容性  
    386         //我的理解是上面c.contains抛出了异常,导致for循环终止,那么必然会导致r != size  
    387         //所以0-w之间是需要保留的数据,同时从w索引开始将剩下没有循环的数据(也就是从r开始的)拷贝回来,也保留  
    388             if (r != size) {  
    389                 System.arraycopy(elementData, r,  
    390                                  elementData, w,  
    391                                  size - r);  
    392                 w += size - r;  
    393             }  
    394         //for循环完毕,检测了所有的元素  
    395         //0-w之间保存了需要留下的数据,w开始以及后面的数据全部清空  
    396             if (w != size) {  
    397                 // clear to let GC do its work  
    398                 for (int i = w; i < size; i++)  
    399                     elementData[i] = null;  
    400                 modCount += size - w;  
    401                 size = w;  
    402                 modified = true;  
    403             }  
    404         }  
    405         return modified;  
    406     }  
    407   
    408 /***************************** Writer and Read Object *************************/  
    409   
    410     //java.io.Serializable的写入函数  
    411     //将ArrayList的“容量、所有的元素值”都写入到输出流中  
    412     private void writeObject(java.io.ObjectOutputStream s)  
    413         throws java.io.IOException{  
    414         // Write out element count, and any hidden stuff  
    415         int expectedModCount = modCount;  
    416         s.defaultWriteObject();  
    417   
    418         // Write out size as capacity for behavioural compatibility with clone()  
    419     //写入“数组的容量”,保持与clone()的兼容性  
    420         s.writeInt(size);  
    421   
    422         //写入“数组的每一个元素”  
    423         for (int i=0; i<size; i++) {  
    424             s.writeObject(elementData[i]);  
    425         }  
    426   
    427         if (modCount != expectedModCount) {  
    428             throw new ConcurrentModificationException();  
    429         }  
    430     }  
    431   
    432     //java.io.Serializable的读取函数:根据写入方式读出  
    433     private void readObject(java.io.ObjectInputStream s)  
    434         throws java.io.IOException, ClassNotFoundException {  
    435         elementData = EMPTY_ELEMENTDATA;  
    436   
    437         // Read in size, and any hidden stuff  
    438         s.defaultReadObject();  
    439   
    440         //从输入流中读取ArrayList的“容量”  
    441         s.readInt(); // ignored  
    442   
    443         if (size > 0) {  
    444             // be like clone(), allocate array based upon size not capacity  
    445             ensureCapacityInternal(size);  
    446   
    447             Object[] a = elementData;  
    448             //从输入流中将“所有元素值”读出  
    449             for (int i=0; i<size; i++) {  
    450                 a[i] = s.readObject();  
    451             }  
    452         }  
    453     }  
    454   
    455 /******************************** Iterators ************************************/  
    456   
    457     /** 
    458     * 该部分的方法重写了AbstractList抽象类中Iterator部分的方法,因为ArrayList继承 
    459     * 了AbstractList,基本大同小异,只是这里针对本类的数组,思想与AbstractList一致 
    460     * 可以参照上一章Collection架构与源码分析的AbatractList部分 
    461     */  
    462     public ListIterator<E> listIterator(int index) {  
    463         if (index < 0 || index > size)  
    464             throw new IndexOutOfBoundsException("Index: "+index);  
    465         return new ListItr(index);  
    466     }  
    467   
    468     public ListIterator<E> listIterator() {  
    469         return new ListItr(0);  
    470     }  
    471   
    472     public Iterator<E> iterator() {  
    473         return new Itr();  
    474     }  
    475   
    476     private class Itr implements Iterator<E> {  
    477         int cursor;       // index of next element to return  
    478         int lastRet = -1; // index of last element returned; -1 if no such  
    479         int expectedModCount = modCount;  
    480   
    481         public boolean hasNext() {  
    482             return cursor != size;  
    483         }  
    484   
    485         @SuppressWarnings("unchecked")  
    486         public E next() {  
    487             checkForComodification();  
    488             int i = cursor;  
    489             if (i >= size)  
    490                 throw new NoSuchElementException();  
    491             Object[] elementData = ArrayList.this.elementData;  
    492             if (i >= elementData.length)  
    493                 throw new ConcurrentModificationException();  
    494             cursor = i + 1;  
    495             return (E) elementData[lastRet = i];  
    496         }  
    497   
    498         public void remove() {  
    499             if (lastRet < 0)  
    500                 throw new IllegalStateException();  
    501             checkForComodification();  
    502   
    503             try {  
    504                 ArrayList.this.remove(lastRet);  
    505                 cursor = lastRet;  
    506                 lastRet = -1;  
    507                 expectedModCount = modCount;  
    508             } catch (IndexOutOfBoundsException ex) {  
    509                 throw new ConcurrentModificationException();  
    510             }  
    511         }  
    512   
    513         final void checkForComodification() {  
    514             if (modCount != expectedModCount)  
    515                 throw new ConcurrentModificationException();  
    516         }  
    517     }  
    518   
    519     private class ListItr extends Itr implements ListIterator<E> {  
    520         ListItr(int index) {  
    521             super();  
    522             cursor = index;  
    523         }  
    524   
    525         public boolean hasPrevious() {  
    526             return cursor != 0;  
    527         }  
    528   
    529         public int nextIndex() {  
    530             return cursor;  
    531         }  
    532   
    533         public int previousIndex() {  
    534             return cursor - 1;  
    535         }  
    536   
    537         @SuppressWarnings("unchecked")  
    538         public E previous() {  
    539             checkForComodification();  
    540             int i = cursor - 1;  
    541             if (i < 0)  
    542                 throw new NoSuchElementException();  
    543             Object[] elementData = ArrayList.this.elementData;  
    544             if (i >= elementData.length)  
    545                 throw new ConcurrentModificationException();  
    546             cursor = i;  
    547             return (E) elementData[lastRet = i];  
    548         }  
    549   
    550         public void set(E e) {  
    551             if (lastRet < 0)  
    552                 throw new IllegalStateException();  
    553             checkForComodification();  
    554   
    555             try {  
    556                 ArrayList.this.set(lastRet, e);  
    557             } catch (IndexOutOfBoundsException ex) {  
    558                 throw new ConcurrentModificationException();  
    559             }  
    560         }  
    561   
    562         public void add(E e) {  
    563             checkForComodification();  
    564   
    565             try {  
    566                 int i = cursor;  
    567                 ArrayList.this.add(i, e);  
    568                 cursor = i + 1;  
    569                 lastRet = -1;  
    570                 expectedModCount = modCount;  
    571             } catch (IndexOutOfBoundsException ex) {  
    572                 throw new ConcurrentModificationException();  
    573             }  
    574         }  
    575     }  
    576   
    577     public List<E> subList(int fromIndex, int toIndex) {  
    578         subListRangeCheck(fromIndex, toIndex, size);  
    579         return new SubList(this, 0, fromIndex, toIndex);  
    580     }  
    581   
    582     static void subListRangeCheck(int fromIndex, int toIndex, int size) {  
    583         if (fromIndex < 0)  
    584             throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);  
    585         if (toIndex > size)  
    586             throw new IndexOutOfBoundsException("toIndex = " + toIndex);  
    587         if (fromIndex > toIndex)  
    588             throw new IllegalArgumentException("fromIndex(" + fromIndex +  
    589                                                ") > toIndex(" + toIndex + ")");  
    590     }  
    591   
    592     private class SubList extends AbstractList<E> implements RandomAccess {  
    593         private final AbstractList<E> parent;  
    594         private final int parentOffset;  
    595         private final int offset;  
    596         int size;  
    597   
    598         SubList(AbstractList<E> parent,  
    599                 int offset, int fromIndex, int toIndex) {  
    600             this.parent = parent;  
    601             this.parentOffset = fromIndex;  
    602             this.offset = offset + fromIndex;  
    603             this.size = toIndex - fromIndex;  
    604             this.modCount = ArrayList.this.modCount;  
    605         }  
    606   
    607         public E set(int index, E e) {  
    608             rangeCheck(index);  
    609             checkForComodification();  
    610             E oldValue = ArrayList.this.elementData(offset + index);  
    611             ArrayList.this.elementData[offset + index] = e;  
    612             return oldValue;  
    613         }  
    614   
    615         public E get(int index) {  
    616             rangeCheck(index);  
    617             checkForComodification();  
    618             return ArrayList.this.elementData(offset + index);  
    619         }  
    620   
    621         public int size() {  
    622             checkForComodification();  
    623             return this.size;  
    624         }  
    625   
    626         public void add(int index, E e) {  
    627             rangeCheckForAdd(index);  
    628             checkForComodification();  
    629             parent.add(parentOffset + index, e);  
    630             this.modCount = parent.modCount;  
    631             this.size++;  
    632         }  
    633   
    634         public E remove(int index) {  
    635             rangeCheck(index);  
    636             checkForComodification();  
    637             E result = parent.remove(parentOffset + index);  
    638             this.modCount = parent.modCount;  
    639             this.size--;  
    640             return result;  
    641         }  
    642   
    643         protected void removeRange(int fromIndex, int toIndex) {  
    644             checkForComodification();  
    645             parent.removeRange(parentOffset + fromIndex,  
    646                                parentOffset + toIndex);  
    647             this.modCount = parent.modCount;  
    648             this.size -= toIndex - fromIndex;  
    649         }  
    650   
    651         public boolean addAll(Collection<? extends E> c) {  
    652             return addAll(this.size, c);  
    653         }  
    654   
    655         public boolean addAll(int index, Collection<? extends E> c) {  
    656             rangeCheckForAdd(index);  
    657             int cSize = c.size();  
    658             if (cSize==0)  
    659                 return false;  
    660   
    661             checkForComodification();  
    662             parent.addAll(parentOffset + index, c);  
    663             this.modCount = parent.modCount;  
    664             this.size += cSize;  
    665             return true;  
    666         }  
    667   
    668         public Iterator<E> iterator() {  
    669             return listIterator();  
    670         }  
    671   
    672         public ListIterator<E> listIterator(final int index) {  
    673             checkForComodification();  
    674             rangeCheckForAdd(index);  
    675             final int offset = this.offset;  
    676   
    677             return new ListIterator<E>() {  
    678                 int cursor = index;  
    679                 int lastRet = -1;  
    680                 int expectedModCount = ArrayList.this.modCount;  
    681   
    682                 public boolean hasNext() {  
    683                     return cursor != SubList.this.size;  
    684                 }  
    685   
    686                 @SuppressWarnings("unchecked")  
    687                 public E next() {  
    688                     checkForComodification();  
    689                     int i = cursor;  
    690                     if (i >= SubList.this.size)  
    691                         throw new NoSuchElementException();  
    692                     Object[] elementData = ArrayList.this.elementData;  
    693                     if (offset + i >= elementData.length)  
    694                         throw new ConcurrentModificationException();  
    695                     cursor = i + 1;  
    696                     return (E) elementData[offset + (lastRet = i)];  
    697                 }  
    698   
    699                 public boolean hasPrevious() {  
    700                     return cursor != 0;  
    701                 }  
    702   
    703                 @SuppressWarnings("unchecked")  
    704                 public E previous() {  
    705                     checkForComodification();  
    706                     int i = cursor - 1;  
    707                     if (i < 0)  
    708                         throw new NoSuchElementException();  
    709                     Object[] elementData = ArrayList.this.elementData;  
    710                     if (offset + i >= elementData.length)  
    711                         throw new ConcurrentModificationException();  
    712                     cursor = i;  
    713                     return (E) elementData[offset + (lastRet = i)];  
    714                 }  
    715   
    716                 public int nextIndex() {  
    717                     return cursor;  
    718                 }  
    719   
    720                 public int previousIndex() {  
    721                     return cursor - 1;  
    722                 }  
    723   
    724                 public void remove() {  
    725                     if (lastRet < 0)  
    726                         throw new IllegalStateException();  
    727                     checkForComodification();  
    728   
    729                     try {  
    730                         SubList.this.remove(lastRet);  
    731                         cursor = lastRet;  
    732                         lastRet = -1;  
    733                         expectedModCount = ArrayList.this.modCount;  
    734                     } catch (IndexOutOfBoundsException ex) {  
    735                         throw new ConcurrentModificationException();  
    736                     }  
    737                 }  
    738   
    739                 public void set(E e) {  
    740                     if (lastRet < 0)  
    741                         throw new IllegalStateException();  
    742                     checkForComodification();  
    743   
    744                     try {  
    745                         ArrayList.this.set(offset + lastRet, e);  
    746                     } catch (IndexOutOfBoundsException ex) {  
    747                         throw new ConcurrentModificationException();  
    748                     }  
    749                 }  
    750   
    751                 public void add(E e) {  
    752                     checkForComodification();  
    753   
    754                     try {  
    755                         int i = cursor;  
    756                         SubList.this.add(i, e);  
    757                         cursor = i + 1;  
    758                         lastRet = -1;  
    759                         expectedModCount = ArrayList.this.modCount;  
    760                     } catch (IndexOutOfBoundsException ex) {  
    761                         throw new ConcurrentModificationException();  
    762                     }  
    763                 }  
    764   
    765                 final void checkForComodification() {  
    766                     if (expectedModCount != ArrayList.this.modCount)  
    767                         throw new ConcurrentModificationException();  
    768                 }  
    769             };  
    770         }  
    771   
    772         public List<E> subList(int fromIndex, int toIndex) {  
    773             subListRangeCheck(fromIndex, toIndex, size);  
    774             return new SubList(this, offset, fromIndex, toIndex);  
    775         }  
    776   
    777         private void rangeCheck(int index) {  
    778             if (index < 0 || index >= this.size)  
    779                 throw new IndexOutOfBoundsException(outOfBoundsMsg(index));  
    780         }  
    781   
    782         private void rangeCheckForAdd(int index) {  
    783             if (index < 0 || index > this.size)  
    784                 throw new IndexOutOfBoundsException(outOfBoundsMsg(index));  
    785         }  
    786   
    787         private String outOfBoundsMsg(int index) {  
    788             return "Index: "+index+", Size: "+this.size;  
    789         }  
    790   
    791         private void checkForComodification() {  
    792             if (ArrayList.this.modCount != this.modCount)  
    793                 throw new ConcurrentModificationException();  
    794         }  
    795     }  
    796 }  
    View Code

    总结一下:

        1). ArrayList实际上是通过一个数组去保存数据的,当我们构造ArrayList时,如果使用默认构造函数,最后ArrayList的默认容量大小是10。

        2). 当ArrayList容量不足以容纳全部元素时,ArrayList会自动扩张容量,新的容量 = 原始容量 + 原始容量 / 2。

        3). ArrayList的克隆函数,即是将全部元素克隆到一个数组中。

        4. ArrayList实现java.io.Serializable的方式。当写入到输出流时,先写入“容量”,再依次写出“每一个元素”;当读出输入流时,先读取“容量”,再依次读取“每一个元素”。

    3. ArrayList遍历方式

        ArrayList支持三种遍历方式,下面我们逐个讨论:

        1). 通过迭代器遍历。即Iterator迭代器。

    Integer value = null;  
    Iterator it = list.iterator();  
    while (it.hasNext()) {  
        value = (Integer)it.next();  
    }  

    2). 随机访问,通过索引值去遍历。由于ArrayList实现了RandomAccess接口,所以它支持通过索引值去随机访问元素。

    Integer value = null;  
    int size = list.size();  
    for (int i = 0; i < size; i++) {  
        value = (Integer)list.get(i);          
    }  

     3). 通过for循环遍历。

    Integer value = null;  
    for (Integer integ : list) {  
        value = integ;  
    }  

     下面写了一个测试用例,比较这三种遍历方式的效率:

    import java.util.*;  
      
    /* 
     * @description ArrayList三种遍历方式效率的测试 
     * @author eson_15 
     */  
    public class ArrayListRandomAccessTest {  
      
        public static void main(String[] args) {  
            List<Integer> list = new ArrayList<Integer>();  
            for (int i=0; i<500000; i++)  
                list.add(i);  
            isRandomAccessSupported(list);//判断是否支持RandomAccess  
            iteratorThroughRandomAccess(list) ;  
            iteratorThroughIterator(list) ;  
            iteratorThroughFor(list) ;  
          
        }  
      
        private static void isRandomAccessSupported(List<Integer> list) {  
            if (list instanceof RandomAccess) {  
                System.out.println("RandomAccess implemented!");  
            } else {  
                System.out.println("RandomAccess not implemented!");  
            }  
      
        }  
      
        public static void iteratorThroughRandomAccess(List<Integer> list) {  
      
            long startTime;  
            long endTime;  
            startTime = System.currentTimeMillis();  
            for (int i=0; i<list.size(); i++) {  
                list.get(i);  
            }  
            endTime = System.currentTimeMillis();  
            long interval = endTime - startTime;  
            System.out.println("RandomAccess遍历时间:" + interval+" ms");  
        }  
      
        public static void iteratorThroughIterator(List<Integer> list) {  
      
            long startTime;  
            long endTime;  
            startTime = System.currentTimeMillis();  
            for(Iterator<Integer> it = list.iterator(); it.hasNext(); ) {  
                it.next();  
            }  
            endTime = System.currentTimeMillis();  
            long interval = endTime - startTime;  
            System.out.println("Iterator遍历时间:" + interval+" ms");  
        }  
      
      
        @SuppressWarnings("unused")  
        public static void iteratorThroughFor(List<Integer> list) {  
      
            long startTime;  
            long endTime;  
            startTime = System.currentTimeMillis();  
            for(Object obj : list)  
                ;  
            endTime = System.currentTimeMillis();  
            long interval = endTime - startTime;  
            System.out.println("For循环遍历时间:" + interval+" ms");  
        }  
    }  

       每次执行的结果会有一点点区别,在这里我统计了6次执行结果,见下表:

     

    RandomAccess(ms)

    Iterator(ms)

    For(ms)

    第一次

    5

    8

    7

    第二次

    4

    7

    7

    第三次

    5

    8

    10

    第四次

    5

    7

    6

    第五次

    5

    8

    7

    第六次

    5

    7

    6

    平均

    4.8

    7.5

    7.1

        由此可见,遍历ArrayList时,使用随机访问(即通过索引号访问)效率最高,而使用迭代器的效率最低。

    4. toArray()异常问题

        当我们调用ArrayList中的toArray()方法时,可能会遇到"java.lang.ClassCastException"异常的情况,下面来讨论下出现的原因:

        ArrayList中提供了2个toArray()方法:

    Object[] toArray()  
    <T> T[] toArray(T[] contents)

    调用toArray()函数会抛出"java.lang.ClassCastException"异常,但是调用toArray(T[] contents)能正常返回T[]。toArray()会抛出异常是因为toArray()返回的是Object[]数组,将Object[]转换为其它类型(比如将Object[]转换为Integer[])则会抛出"java.lang.ClassCastException"异常,因为java不支持向下转型。解决该问题的办法是调用<T> T[] toArray(T[] contents),而不是Object[] toArray()。

        调用<T> T[] toArray(T[] contents)返回T[]可以通过以下几种方式实现:

    // toArray(T[] contents)调用方式一  
    public static Integer[] vectorToArray1(ArrayList<Integer> v) {  
        Integer[] newText = new Integer[v.size()];  
        v.toArray(newText);  
        return newText;  
    }  
      
    // toArray(T[] contents)调用方式二。<span style="color:#FF6666;">最常用!</span>  
    public static Integer[] vectorToArray2(ArrayList<Integer> v) {  
        Integer[] newText = (Integer[])v.toArray(new Integer[v.size()]);  
        return newText;  
    }  
      
    // toArray(T[] contents)调用方式三  
    public static Integer[] vectorToArray3(ArrayList<Integer> v) {  
        Integer[] newText = new Integer[v.size()];  
        Integer[] newStrings = (Integer[])v.toArray(newText);  
        return newStrings;  
    }  

    三种方式都大同小异。

        ArrayList源码就讨论这么多,如有错误,欢迎留言指正~

  • 相关阅读:
    java通过ST4使用模板字符串
    使用 docker创建redis实例并且连接
    Docker 认证成功后还是无法push构建好的镜像
    记录一次在openwrt中折腾docker
    全局模式、PAC模式、直连模式的区别
    Vue Router中调用this.$router.push() 时,location使用path无法传入params
    liunx之系统
    liunx之通配符&正则表达式
    liunx之基础
    liunx之find命令
  • 原文地址:https://www.cnblogs.com/shanheyongmu/p/6428604.html
Copyright © 2011-2022 走看看