• ArrayList源码分析


      首先,来看ArrayList的定义:

    1 public class ArrayList<E> extends AbstractList<E>
    2         implements List<E>, RandomAccess, Cloneable, java.io.Serializable

    ArrayList继承于AbstractList类,并实现了List、RandomAccess、Cloneable和Serializable接口。

    1     /**
    2      * 定义ArrayList内部保存数据用的数组。
    3      */
    4     private transient Object[] elementData;
    5 
    6     /**
    7      * 定义ArrayList的实际包含数据的长度。
    8      */
    9     private int size;

    看构造方法:

     1     /**
     2      * 根据传入的initialCapacity来定义一个数组。如果initialCapacity小于0,则抛出IllegalArgument异常。
     3      */
     4     public ArrayList(int initialCapacity) {
     5     super();
     6         if (initialCapacity < 0)
     7             throw new IllegalArgumentException("Illegal Capacity: "+
     8                                                initialCapacity);
     9     this.elementData = new Object[initialCapacity];
    10     }
    11 
    12     /**
    13      * 默认创建一个长度为10的Object类型数组。
    14      */
    15     public ArrayList() {
    16     this(10);
    17     }
    18     
    19      /**
    20      * 根据传入的集合来初始化。如果传入的集合的toArray()方法返回的不是Object[]类型的,则利用Arrays.copyOf来转为Object[]类型
    21      */
    22     public ArrayList(Collection<? extends E> c) {
    23     elementData = c.toArray();
    24     size = elementData.length;
    25     // c.toArray might (incorrectly) not return Object[] (see 6260652)
    26     if (elementData.getClass() != Object[].class)
    27         elementData = Arrays.copyOf(elementData, size, Object[].class);
    28     }

    注意第3个构造方法当中有一个注释:c.toArray might (incorrectly) not return Object[] (see 6260652),意识是说c.toArray不一定总是返回Object[]类型的数组,这是incorrectly的,大家可以参照

    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6260652来看看这个java的bug。

    下面开始分析ArrayList的各个方法:

    ①、trimToSize()

     1     /**
     2      * 此方法将数组elementData中没有用来存储数据的内存释放出来,减少占用的内存空间。
     3      * 使得list的size和capacity大小一样。
     4      */
     5     public void trimToSize() {
     6     modCount++;
     7     int oldCapacity = elementData.length;
     8     if (size < oldCapacity) {
     9             elementData = Arrays.copyOf(elementData, size);
    10     }
    11     }

    ②、ensureCapacity()

     1     /**
     2      * 数组扩容用的方法。如果传入的minCapacity还没有以前的容量大,则什么都不做;如果比以前的容量大,那也不一定就按照minCapacity的大小来扩容。
     3      * 首先,将以前的容量扩大到1.5倍再加上1,如果扩大后的容量比minCapacity小,则容量最终还是扩大到minCapacity,否则就扩大到以前的1.5倍加上1的大小。
     4      * 也就是说,扩容至少扩大到以前的1.5倍再加上1。
     5      */
     6     public void ensureCapacity(int minCapacity) {
     7     modCount++;
     8     int oldCapacity = elementData.length;
     9     if (minCapacity > oldCapacity) {
    10         Object oldData[] = elementData;
    11         int newCapacity = (oldCapacity * 3)/2 + 1;
    12             if (newCapacity < minCapacity)
    13         newCapacity = minCapacity;
    14             // minCapacity is usually close to size, so this is a win:
    15             elementData = Arrays.copyOf(elementData, newCapacity);
    16     }
    17     }

    ③、size()和isEmpty()

     1     /**
     2      * 返回list的大小,注意不是数组的容量大小。
     3      */
     4     public int size() {
     5     return size;
     6     }
     7 
     8     /**
     9      * 根据list的大小是否为0来判断list是否为空
    10      */
    11     public boolean isEmpty() {
    12     return size == 0;
    13     }

    ④、indexOf()和lastIndexOf()

     1     /**
     2      * 从数组下标0开始查找o,找到的话就返回其下标,如果没有找到,则返回-1。
     3      */
     4     public int indexOf(Object o) {
     5     if (o == null) {
     6         for (int i = 0; i < size; i++)
     7         if (elementData[i]==null)
     8             return i;
     9     } else {
    10         for (int i = 0; i < size; i++)
    11         if (o.equals(elementData[i]))
    12             return i;
    13     }
    14     return -1;
    15     }
    16 
    17     /**
    18      * 从数组最后一位开始向前查找o,找到的话返回其下标,否则返回-1。
    19      */
    20     public int lastIndexOf(Object o) {
    21     if (o == null) {
    22         for (int i = size-1; i >= 0; i--)
    23         if (elementData[i]==null)
    24             return i;
    25     } else {
    26         for (int i = size-1; i >= 0; i--)
    27         if (o.equals(elementData[i]))
    28             return i;
    29     }
    30     return -1;
    31     }

    ⑤、contains()

    1     /**
    2      * 调用indexOf方法来判断o是否存在于list中。
    3      */
    4     public boolean contains(Object o) {
    5     return indexOf(o) >= 0;
    6     }

    ⑥、clone()

     1     /**
     2      * 此方法为浅层复制,不是深层复制
     3      */
     4     public Object clone() {
     5     try {
     6         ArrayList<E> v = (ArrayList<E>) super.clone();
     7         v.elementData = Arrays.copyOf(elementData, size);
     8         v.modCount = 0;
     9         return v;
    10     } catch (CloneNotSupportedException e) {
    11         // this shouldn't happen, since we are Cloneable
    12         throw new InternalError();
    13     }
    14     }

    ⑦、toArray()和toArray(T[] a)

     1     /**
     2      * 将list转为数组,注意是重新创建了一个长度相同(为size)的数组,与list内部的数组不是同一个
     3      */
     4     public Object[] toArray() {
     5         return Arrays.copyOf(elementData, size);
     6     }
     7 
     8     /**
     9      * 将list转为数组,数组的类型由传入的参数a决定。
    10      * 如果a的长度小于list的长度,则从list的第一个元素开始直至填满a;
    11      * 如果a的长度大于list的长度,则把list的元素全部填入a后,将a[a.length]设为null。
    12      */
    13     public <T> T[] toArray(T[] a) {
    14         if (a.length < size)
    15             // Make a new array of a's runtime type, but my contents:
    16             return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    17     System.arraycopy(elementData, 0, a, 0, size);
    18         if (a.length > size)
    19             a[size] = null;
    20         return a;
    21     }

    ⑧、RangeCheck()

     1     /**
     2      * 此方法为判断index是否超出list的长度size,注意不是list的容量。
     3      * 如果超出,则抛出IndexOutOfBounds异常。
     4      * list的很多方法都会先调用此方法来做判断。
     5      */
     6     private void RangeCheck(int index) {
     7     if (index >= size)
     8         throw new IndexOutOfBoundsException(
     9         "Index: "+index+", Size: "+size);
    10     }

    接下来的是一些访问list的方法:

      1     /**
      2      * 首先调用RangeCheck方法判断index合法性,然后直接返回数组对应下标的值。
      3      */
      4     public E get(int index) {
      5     RangeCheck(index);
      6 
      7     return (E) elementData[index];
      8     }
      9 
     10     /**
     11      * 首先调用RangeCheck方法判断index的合法性,然后定义一个变量oldValue指向数组对应下标的值,
     12      * 再将此下标的值换为传入的参数element,最后返回旧的值oldValue。
     13      */
     14     public E set(int index, E element) {
     15     RangeCheck(index);
     16 
     17     E oldValue = (E) elementData[index];
     18     elementData[index] = element;
     19     return oldValue;
     20     }
     21 
     22     /**
     23      * 此方法为往list的下标为size的地方添加元素e。
     24      * 首先对数组进行扩容,然后将数组下标为size的元素赋为e。
     25      */
     26     public boolean add(E e) {
     27     ensureCapacity(size + 1);  // Increments modCount!!
     28     elementData[size++] = e;   // 这种写法一举两得,既赋了值,又把size加了1,可以省下一行代码。
     29     return true;
     30     }
     31 
     32     /**
     33      * 此方法为在指定下标处添加元素。
     34      * 首先判断传入的index是否合法,注意index可以等于size,这时应该相当于前面的add(E e)方法。
     35      * 然后也是先把数组扩容,接着通过System的arraycopy方法把数组从下表index开始到size-1处的元素整体往后移一位。
     36      */
     37     public void add(int index, E element) {
     38     if (index > size || index < 0)
     39         throw new IndexOutOfBoundsException(
     40         "Index: "+index+", Size: "+size);
     41 
     42     ensureCapacity(size+1);  // Increments modCount!!
     43     System.arraycopy(elementData, index, elementData, index + 1,
     44              size - index);
     45     elementData[index] = element;
     46     size++;
     47     }
     48 
     49     /**
     50      * 此方法为删除指定下标处的元素。
     51      * 首先判断index的合法性。然后定义一个变量oldValue获取数组指定下标处的元素。
     52      * 然后定义numMoved变量获取(size - index - 1)的值,如果为0,则表示index为list的最后一个元素的下标,那么就木有必要再进行数组元素的移动了。
     53      * 否则index不是最后一个元素的下标,那么把数组里的下标为index+1的元素开始到最后一个元素全部往前移动一位。
     54      * 再将list的最后一位赋值为null,同时将size减少1。
     55      * 最后返回oldValue,即被删除的元素。
     56      */
     57     public E remove(int index) {
     58     RangeCheck(index);
     59 
     60     modCount++;
     61     E oldValue = (E) elementData[index];
     62 
     63     int numMoved = size - index - 1;
     64     if (numMoved > 0)
     65         System.arraycopy(elementData, index+1, elementData, index,
     66                  numMoved);
     67     elementData[--size] = null; // Let gc do its work
     68 
     69     return oldValue;
     70     }
     71 
     72     /**
     73      * 删除数组里第一个值为o的元素。
     74      * 先判断o是否为null,如果是null,则遍历数组,发现null的话,删除null,并返回true;
     75      * 如果不是null,则遍历数组,调用o的equals方法一次和数组元素进行比较,如果为true则删除此元素并返回true。
     76      */
     77     public boolean remove(Object o) {
     78     if (o == null) {
     79             for (int index = 0; index < size; index++)
     80         if (elementData[index] == null) {
     81             fastRemove(index);
     82             return true;
     83         }
     84     } else {
     85         for (int index = 0; index < size; index++)
     86         if (o.equals(elementData[index])) {
     87             fastRemove(index);
     88             return true;
     89         }
     90         }
     91     return false;
     92     }
     93 
     94     /*
     95      * 私有的删除方法,与remove方法有两点区别:①不会返回被删除的元素;②不会调用RangeCheck方法进行check。
     96      */
     97     private void fastRemove(int index) {
     98         modCount++;
     99         int numMoved = size - index - 1;
    100         if (numMoved > 0)
    101             System.arraycopy(elementData, index+1, elementData, index,
    102                              numMoved);
    103         elementData[--size] = null; // Let gc do its work
    104     }
    105 
    106     /**
    107      * 此方法是清空list,遍历数组,将里面所有的元素都赋值为null。同时,size也赋值为0。
    108      */
    109     public void clear() {
    110     modCount++;
    111 
    112     // Let gc do its work
    113     for (int i = 0; i < size; i++)
    114         elementData[i] = null;
    115 
    116     size = 0;
    117     }
    118 
    119     /**
    120      * Appends all of the elements in the specified collection to the end of
    121      * this list, in the order that they are returned by the
    122      * specified collection's Iterator.  The behavior of this operation is
    123      * undefined if the specified collection is modified while the operation
    124      * is in progress.  (This implies that the behavior of this call is
    125      * undefined if the specified collection is this list, and this
    126      * list is nonempty.)
    127      *
    128      * @param c collection containing elements to be added to this list
    129      * @return <tt>true</tt> if this list changed as a result of the call
    130      * @throws NullPointerException if the specified collection is null
    131      */
    132     public boolean addAll(Collection<? extends E> c) {
    133     Object[] a = c.toArray();
    134         int numNew = a.length;
    135     ensureCapacity(size + numNew);  // Increments modCount
    136         System.arraycopy(a, 0, elementData, size, numNew);
    137         size += numNew;
    138     return numNew != 0;
    139     }
    140 
    141     /**
    142      * 把此方法传入的集合c依次从list的下标index开始添加,同时把原先下标index往后的所有元素再往后移动c.size()位。
    143      */
    144     public boolean addAll(int index, Collection<? extends E> c) {
    145     if (index > size || index < 0)
    146         throw new IndexOutOfBoundsException(
    147         "Index: " + index + ", Size: " + size);
    148 
    149     Object[] a = c.toArray();
    150     int numNew = a.length;
    151     ensureCapacity(size + numNew);  // Increments modCount
    152 
    153     int numMoved = size - index;
    154     if (numMoved > 0)
    155         System.arraycopy(elementData, index, elementData, index + numNew,
    156                  numMoved);
    157 
    158         System.arraycopy(a, 0, elementData, index, numNew);
    159     size += numNew;
    160     return numNew != 0;
    161     }
    162 
    163     /**
    164      * 删除下标从fromIndex到toIndex-1的元素。
    165      * 首先将下标从toIndex到size-1的元素全部向前移动size-toIndex位,
    166      * 然后将list的后toIndex-fromIndex位的元素的值赋为null。
    167      */
    168     protected void removeRange(int fromIndex, int toIndex) {
    169     modCount++;
    170     int numMoved = size - toIndex;
    171         System.arraycopy(elementData, toIndex, elementData, fromIndex,
    172                          numMoved);
    173 
    174     // Let gc do its work
    175     int newSize = size - (toIndex-fromIndex);
    176     while (size != newSize)
    177         elementData[--size] = null;
    178     }

    最后,还有两个方法是序列化时处理用的:

     1     /**
     2      * 序列化时,先执行defaultWriteObject()方法;然后再把数组的长度也写入流中,最后分别把数组中的每个元素都写到流中。
     3      */
     4     private void writeObject(java.io.ObjectOutputStream s)
     5         throws java.io.IOException{
     6     // Write out element count, and any hidden stuff
     7     int expectedModCount = modCount;
     8     s.defaultWriteObject();
     9 
    10         // Write out array length
    11         s.writeInt(elementData.length);
    12 
    13     // Write out all elements in the proper order.
    14     for (int i=0; i<size; i++)
    15             s.writeObject(elementData[i]);
    16 
    17     if (modCount != expectedModCount) {
    18             throw new ConcurrentModificationException();
    19         }
    20 
    21     }
    22 
    23     /**
    24      * 从流中读取元素,先调用defaultReadObject()方法,然后依次读取数组长度,接着是数组当中的每个元素信息。
    25      * 和writeObject的写入顺序一样。
    26      */
    27     private void readObject(java.io.ObjectInputStream s)
    28         throws java.io.IOException, ClassNotFoundException {
    29     // Read in size, and any hidden stuff
    30     s.defaultReadObject();
    31 
    32         // Read in array length and allocate array
    33         int arrayLength = s.readInt();
    34         Object[] a = elementData = new Object[arrayLength];
    35 
    36     // Read in all elements in the proper order.
    37     for (int i=0; i<size; i++)
    38             a[i] = s.readObject();
    39     }

    终于看完了,其实ArrayList的父类AbstractList中还有很多重要的实现,不过下回分解吧。

  • 相关阅读:
    C#下给数字前面补0的方法
    Notepad++ xml 文件不能语法着色的问题解决
    excel 技巧
    编译时报警 implicit declaration of function
    配置ASP.NET平台时遇到的“访问IIS元数据库失败”解决方案
    用360安全卫士批量本地快速给系统打补丁【转贴】
    新雨情系统随笔
    我的开发博客开通了
    JQuery资料
    IGNORE_DUP_KEY = OF的作用
  • 原文地址:https://www.cnblogs.com/huashui/p/3200504.html
Copyright © 2020-2023  润新知