zoukankan      html  css  js  c++  java
  • 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中还有很多重要的实现,不过下回分解吧。

  • 相关阅读:
    DVWA 黑客攻防演练(十)反射型 XSS 攻击 Reflected Cross Site Scripting
    DVWA 黑客攻防演练(九) SQL 盲注 SQL Injection (Blind)
    DVWA 黑客攻防演练(八)SQL 注入 SQL Injection
    DVWA 黑客攻防演练(七)Weak Session IDs
    DVWA 黑客攻防演练(六)不安全的验证码 Insecure CAPTCHA
    DVWA 黑客攻防演练(五)文件上传漏洞 File Upload
    工作流表结构设计
    Visual Studio 2019尝鲜----新建空项目体验
    《使用CSLA 2019:CSLA .NET概述》原版和机译文档下载
    .NET快速开发平台的在线预览
  • 原文地址:https://www.cnblogs.com/huashui/p/3200504.html
Copyright © 2011-2022 走看看