Java類集架構之ArrayList源碼剖析

來源:互聯網
上載者:User

標籤:java集合   arraylist   


ArrayList

基於數組實現,本質上是對象引用的一個變長數組,能夠動態增加或減小其大小。

不是安全執行緒的,只能用在單線程環境下。多線程環境下可以考慮用Collection.synchronizedList(List l)函數返回一個安全執行緒的ArrayList類,也可以使用concurrent並發包下的

CopyOnWriteArrayList類

下面直接貼ArrayList的Java實現,來源JDK1.8.0_25/src.zip。

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{//實現了RandomAccess介面,支援快速隨機訪問//實現了Cloneable介面,能夠被複製//實現了Serializable介面,支援序列化   private static final long serialVersionUID = 8683452581122892189L;//序列版本號碼   private static final int DEFAULT_CAPACITY = 10;//預設初始容量   private static final Object[] EMPTY_ELEMENTDATA = {};//空數組   private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//預設空數組   transient Object[] elementData; // 不會被序列化   private int size;//ArrayList實際元素容量   //建構函式1---帶容量大小的建構函式   public ArrayList(int initialCapacity) {       if (initialCapacity > 0) {           this.elementData = new Object[initialCapacity];//指定大小數組       } else if (initialCapacity == 0) {           this.elementData = EMPTY_ELEMENTDATA;       } else {           throw new IllegalArgumentException("Illegal Capacity: "+                                              initialCapacity);       }   }   //建構函式2---無參建構函式,不指定大小時,預設構造大小為10的數組   public ArrayList() {       this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;   }   //建構函式3---構造一個包含指定collection元素的列表,這些元素是按collection迭代器返回他們的順序排列的   public ArrayList(Collection<? extends E> c) {       elementData = c.toArray();       if ((size = elementData.length) != 0) {           // c.toArray might (incorrectly) not return Object[] (see 6260652)       //http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6260652   可查看bug庫           if (elementData.getClass() != Object[].class)               elementData = Arrays.copyOf(elementData, size, Object[].class);       } else {           // replace with empty array.           this.elementData = EMPTY_ELEMENTDATA;       }   }   //將當前容量設為實際容量   public void trimToSize() {       modCount++;//fast-fail機制,訪問中如果修改集合會拋出 ConcurrentModificationException 異常       if (size < elementData.length) {           elementData = (size == 0)? EMPTY_ELEMENTDATA: Arrays.copyOf(elementData, size);       }   }   //增加容量為minCapacity   public void ensureCapacity(int minCapacity) {       int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)?0:DEFAULT_CAPACITY;            if (minCapacity > minExpand) {           ensureExplicitCapacity(minCapacity);       }   }   private void ensureCapacityInternal(int minCapacity) {       if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {           minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);       }       ensureExplicitCapacity(minCapacity);   }   private void ensureExplicitCapacity(int minCapacity) {       modCount++;       // overflow-conscious code       if (minCapacity - elementData.length > 0)           grow(minCapacity);   }   private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//可分配的最大容量   //每次重新分配記憶體時,新的容量為舊的1.5倍     //但是如果分配後超過可以分配的記憶體範圍分配Integer.MAX_VALUE大小 ,則比較要分配的和最大可分配的容量大小,如果大於分配Integer.MAX_VALUE,如果小於,分配最大容量大小   private void grow(int minCapacity) {       // overflow-conscious code       int oldCapacity = elementData.length;       int newCapacity = oldCapacity + (oldCapacity >> 1);//設定新的容量 = 原始容量*1.5       if (newCapacity - minCapacity < 0)//增加的容量不夠           newCapacity = minCapacity;       if (newCapacity - MAX_ARRAY_SIZE > 0)           newCapacity = hugeCapacity(minCapacity);       // minCapacity is usually close to size, so this is a win:       elementData = Arrays.copyOf(elementData, newCapacity);   }   private static int hugeCapacity(int minCapacity) {       if (minCapacity < 0) // overflow           throw new OutOfMemoryError();       return (minCapacity > MAX_ARRAY_SIZE) ?           Integer.MAX_VALUE :           MAX_ARRAY_SIZE;   }   public int size() {       return size;   }   //是否為空白   public boolean isEmpty() {       return size == 0;   }   //是否包含指定元素o   public boolean contains(Object o) {       return indexOf(o) >= 0;   }   //返回指定元素位置,若沒有返回-1,尋找的元素容許為null   public int indexOf(Object o) {       if (o == null) {           for (int i = 0; i < size; i++)               if (elementData[i]==null)                   return i;       } else {           for (int i = 0; i < size; i++)               if (o.equals(elementData[i]))                   return i;       }       return -1;   }   //返回最後一次出現的位置,若沒有返回-1   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;   }   //複製函數   public Object clone() {       try {           ArrayList<?> v = (ArrayList<?>) super.clone();           v.elementData = Arrays.copyOf(elementData, size);           v.modCount = 0;           return v;       } catch (CloneNotSupportedException e) {           // this shouldn't happen, since we are Cloneable           throw new InternalError(e);       }   }   public Object[] toArray() {       return Arrays.copyOf(elementData, size);   }   @SuppressWarnings("unchecked")   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;   }   // Positional Access Operations   @SuppressWarnings("unchecked")   E elementData(int index) {       return (E) elementData[index];   }   /**    * Returns the element at the specified position in this list.    *    * @param  index index of the element to return    * @return the element at the specified position in this list    * @throws IndexOutOfBoundsException {@inheritDoc}    */   public E get(int index) {       rangeCheck(index);       return elementData(index);   }   public E set(int index, E element) {       rangeCheck(index);       E oldValue = elementData(index);       elementData[index] = element;       return oldValue;   }   public boolean add(E e) {       ensureCapacityInternal(size + 1);  // Increments modCount!!       elementData[size++] = e;       return true;   }//指定位置添加元素,原來位置元素並沒有消失,只是後移了一位,即將當前位於該位置的元素以及所有後續元素右移一個位置。     public void add(int index, E element) {       rangeCheckForAdd(index);       ensureCapacityInternal(size + 1);  // Increments modCount!!       //將 elementData中從Index位置開始、長度為size-index的元素,拷貝到從下標為index+1位置開始的新的elementData數組中       System.arraycopy(elementData, index, elementData, index + 1,                        size - index);       elementData[index] = element;       size++;   }   //去除指定位置元素,該位置後所有元素前移一位   public E remove(int index) {       rangeCheck(index);       modCount++;       E oldValue = elementData(index);       int numMoved = size - index - 1;       if (numMoved > 0)           System.arraycopy(elementData, index+1, elementData, index,numMoved);       elementData[--size] = null; // clear to let GC do its work       return oldValue;   }   //移除列表首次出現的指定元素,如果不存在返回false   public boolean remove(Object o) {       if (o == null) {           for (int index = 0; index < size; index++)               if (elementData[index] == null) {                   fastRemove(index);                   return true;               }       } else {           for (int index = 0; index < size; index++)               if (o.equals(elementData[index])) {                   fastRemove(index);                   return true;               }       }       return false;   }   private void fastRemove(int index) {       modCount++;       int numMoved = size - index - 1;       if (numMoved > 0)           System.arraycopy(elementData, index+1, elementData, index,                            numMoved);       elementData[--size] = null; // clear to let GC do its work   }   public void clear() {       modCount++;       // clear to let GC do its work       for (int i = 0; i < size; i++)           elementData[i] = null;       size = 0;   }   public boolean addAll(Collection<? extends E> c) {       Object[] a = c.toArray();       int numNew = a.length;       ensureCapacityInternal(size + numNew);  // Increments modCount       System.arraycopy(a, 0, elementData, size, numNew);       size += numNew;       return numNew != 0;   }   public boolean addAll(int index, Collection<? extends E> c) {       rangeCheckForAdd(index);       Object[] a = c.toArray();       int numNew = a.length;       ensureCapacityInternal(size + numNew);  // Increments modCount       int numMoved = size - index;       if (numMoved > 0)           System.arraycopy(elementData, index, elementData, index + numNew,                            numMoved);       System.arraycopy(a, 0, elementData, index, numNew);       size += numNew;       return numNew != 0;   }   protected void removeRange(int fromIndex, int toIndex) {       modCount++;       int numMoved = size - toIndex;       System.arraycopy(elementData, toIndex, elementData, fromIndex,                        numMoved);       // clear to let GC do its work       int newSize = size - (toIndex-fromIndex);       for (int i = newSize; i < size; i++) {           elementData[i] = null;       }       size = newSize;   }

構造方法:

ArrayList的構造方法有3種,參數可以指定容量大小,可以為空白(此時會構造一個預設大小為10的空數組),也可以由集合c中的元素來初始化一個數組。

容量增長方法:

關於ArrayList的容量增長方法可以見grow()。ArrayList在每次增加元素時,都要間接調用該方法來確保容量。可分配最大容量為MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8

但是實際最大分配容量可能為 Integer.MAX_VALUE。

在增加元素的過程中,如果當前容量不足以容納元素,就設定為新的容量為舊的容量的1.5倍左右,以前版本是

newCapacity = (oldCapacity * 3)/2 + 1; 
JDK1.8採用的方法是:

newCapacity = oldCapacity + (oldCapacity >> 1);
主要是移位操作比乘法除法更快一些

如果擴容後的新容量依然不夠,則直接設定新容量為傳入的參數(minCapacity)。如果擴容後新的容量比容許的最大容量MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8還要大,則不管滿不滿足要求,設定容量為Integer.MAX_VALUE,這也是前面說容許最大分配容量為MAX_ARRAY_SIZE,但是實際最大分配容量可能為 Integer.MAX_VALUE的原因了。當然,最小分配的容量為預設容量10,即使指定分配容量小於10,也會分配容量10,

說明:

尋找元素時,可以尋找null元素索引,從源碼中可以看到,尋找元素時,是區分null和非null的

必須說明的是:擴容後,還要將原來的元素拷貝到一個新的數組中,非常的耗時,因此建議在事Crowdsourced Security Testing道元素數量的情況下,才使用ArrayList,否則建議使用LinkedList

ArrayList基於數組實現,那麼可以通過下標索引直接尋找指定位置的元素,因此尋找效率高,但是在插入和刪除元素的過程中,要大量移動元素,效率很低。





Java類集架構之ArrayList源碼剖析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.