ArrayList源碼分析

  首先,來看ArrayList的定義:java

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;

看構造方法:app

 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的,你們能夠參照dom

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6260652來看看這個java的bug。this

下面開始分析ArrayList的各個方法:spa

①、trimToSize()code

 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()blog

 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中還有不少重要的實現,不過下回分解吧。

相關文章
相關標籤/搜索