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中还有很多重要的实现,不过下回分解吧。

posted @ 2013-07-19 14:34  画水  阅读(267)  评论(0编辑  收藏  举报