1、ArrayList概述:
ArrayList是List介面的可變數組的實現。實現了所有可選列表操作,可以包含包括null任何元素。除了實現List介面外,此類還提供一些方法來操作內部用來儲存列表的數組的大小。(此類大致上等同於Vector 類,除了此類是不同步的。)
每個ArrayList都有一個容量,該容量是用來儲存列表元素的數組大小。它總是至少等於列表的大小。隨著向ArrayList中增加元素,ArrayList的容量也隨之增加。添加大量元素 前,應用程式也可以使用ensureCapacity操作來增加ArrayList執行個體的容量,這可以減少遞增式再分配的數量。
注意,此實現不是同步的。如果多個線程同時訪問一個 ArrayList 執行個體,而其中至少一個線程從結構上修改了列表,那麼它必須 保持外部同步。這一般通過對自然封裝該列表的對象進行同步操作來完成。如果不存在這樣的對象,則應該使用Collections.synchronizedList 方法將該列表“封裝”起來。
ArrayList繼承AbstractList,實現了List、RandomAccess、Cloneable和java.io.Serializable介面:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
內部定義了一個Object類型的數組來儲存,transient的意思是不進行序列化,這跟Serializable相對。
private transient Object[] elementData;
ArrayList的長度
private int size;
三個建構函式:
public ArrayList(int initialCapacity) {//指定ArrayList初始容量大小 super(); if (initialCapacity < 0)//初始容量不能小於0,否則拋出IllegalArgumentException異常 throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity];} public ArrayList() {//預設使用初始容量為10 this(10);} public ArrayList(Collection<? extends E> c) {//將Collection轉換為ArrayList elementData = c.toArray();//調用toArray()方法,將collection轉換為數組,collection為null,此處便會拋出NullPointerException size = elementData.length; // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class);}
參數是Collection的建構函式需要重點說明一下:這裡的問題是由於Arrays.asList()方法造成的,當Arrays.asList(T
t)方法中參數類型是Object的子類,比如String類型時,該方法傳回值做為參數傳遞給ArrayList建構函式,那麼執行該建構函式中的過程中調用toArray()方法時,由於使用的是clone()方法,所以會返回String[]類型的數組,而並非Obejct[]類型的數組,執行下面代碼中的print方法也是可以看得到傳回值類型的。此時再向toArray()返回對象中增加Object對象就會拋出異常。具體的講解可以參考http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6260652
List<Object> list = new ArrayList<Object>(Arrays.asList("test1", "test2"));//返回String[],而Obejct[]類型//System.out.println(Arrays.asList("foo", "bar").toArray());//將Object對象增加到list中時就會拋出ArrayStoreException list.set(0, new Object());
當記憶體緊張的時候會用到trimToSize:
public void trimToSize() { modCount++;//已從結構上改變此列表的次數,表明該方法會從結構上修改列表 int oldCapacity = elementData.length; if (size < oldCapacity) {//將當前elementData的長度與size比較,如果size較小,則將elementData長度修改為size。 elementData = Arrays.copyOf(elementData, size); }}
擴充數組長度ensureCapacity:將長度擴充到oldsize的1.5倍+1,如果還夠長,就使用指定的長度。
public void ensureCapacity(int minCapacity) { modCount++;//與trimToSize相似,都是從結構上改變了列表 int oldCapacity = elementData.length; if (minCapacity > oldCapacity) {Object oldData[] = elementData;int newCapacity = (oldCapacity * 3)/2 + 1;//如果指定的參數比原長度大,則建立一個1.5倍+1長度的數組,把元素放入其中。 if (newCapacity < minCapacity) newCapacity = minCapacity;//如果長度還是不夠,則使用指定參數的長度大小 // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }}
返回ArrayList的長度大小:
public int size() { return size;}
判斷ArrayList的是否為空白:
public boolean isEmpty() { return size == 0;}
找出指定對象在ArrayList中第一次出現的下標:
public int indexOf(Object o) {//elementData.length與size是不一樣的 if (o == null) { for (int i = 0; i < size; i++)//如果參數為Null,則從下標是0的位置開始遍曆ArrayList,直到找到第一個元素為null的下標值 if (elementData[i]==null) return i; } else {for (int i = 0; i < size; i++)//如果參數不為Null,則遍曆ArrayList中,與指定參數相equals的元素,返回下標值 if (o.equals(elementData[i])) return i;} return -1;//如果都沒有找到,則返回-1}
找出指定對象在ArrayList中最後一次出現的下標:
public int lastIndexOf(Object o) { if (o == null) { for (int i = size-1; i >= 0; i--) if (elementData[i]==null) return i; } else { for (int i = size-1; i >= 0; i--) if (o.equals(elementData[i])) return i; } return -1;}
判斷是否包含指定參數的元素,使用equals判斷:
public boolean contains(Object o) { return indexOf(o) >= 0;}
重寫clone()方法,即數組copy和重設modCount:
public Object clone() { try { ArrayList<E> v = (ArrayList<E>) super.clone(); v.elementData = Arrays.copyOf(elementData, size);//數組copy v.modCount = 0;//重設 return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(); }}
轉換為數組:
public Object[] toArray() { return Arrays.copyOf(elementData, size);}
toArray(T[] a):不太明白做什麼用
public <T> T[] toArray(T[] a) { if (a.length < size) // Make a new array of a's runtime type, but my contents: return (T[]) Arrays.copyOf(elementData, size, a.getClass()); System.arraycopy(elementData, 0, a, 0, size); if (a.length > size) a[size] = null; return a;}
檢查指定參數索引是否正確:
private void RangeCheck(int index) { if (index >= size) throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);}
獲得指定索引的元素,參數不合理會拋出IndexOutOfBoundsException:
public E get(int index) { RangeCheck(index); return (E) elementData[index];}
總以為set返回為void呢,今天看了才知道理解有誤。傳回值是未替換前位於指定索引的元素
public E set(int index, E element) { RangeCheck(index); E oldValue = (E) elementData[index]; elementData[index] = element; return oldValue;}
將指定元素添加到此列表尾部:
public boolean add(E e) { ensureCapacity(size + 1); // Increments modCount!! elementData[size++] = e;//增加到列表尾部 return true;}
將指定元素添加到指定的索引上:
public void add(int index, E element) { if (index > size || index < 0) throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size); ensureCapacity(size+1); // Increments modCount!! //將列表從index開始到最後-1的元素,拷貝到index+1到最後的位置上 System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++;}