Java集合架構ArrayList源碼分析(一)_java

來源:互聯網
上載者:User

ArrayList底層維護的是一個動態數組,每個ArrayList執行個體都有一個容量。該容量是指用來儲存列表元素的數組的大小。它總是至少等於列表的大小。隨著向 ArrayList 中不斷添加元素,其容量也自動成長。

 ArrayList不是同步的(也就是說不是安全執行緒的),如果多個線程同時訪問一個ArrayList執行個體,而其中至少一個線程從結構上修改了列表,那麼它必須保持外部同步,在多線程環境下,可以使用Collections.synchronizedList方法聲明一個安全執行緒的ArrayList,例如:
List arraylist = Collections.synchronizedList(new ArrayList());
下面通過ArrayList的源碼來分析其原理。
1、ArrayList的構造方法:ArrayList提供了三種不同的構造方法
1) ArrayList(),構造一個初始容量為 10 的空列表。
2) ArrayList(int initialCapacity),構造一個具有指定初始容量的空列表。
3) ArrayList(Collection<? extends E> c),構造一個包含指定 collection 的元素的列表,這些元素是按照該 collection 的迭代器返回它們的順序排列的。

源碼如下: 

private transient Object[] elementData;public ArrayList(int initialCapacity) {  super();  if (initialCapacity < 0)    throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);  this.elementData = new Object[initialCapacity]; //產生一個長度為10的Object類型的數組 }   public ArrayList() {  this(10); //調用ArrayList(int i) }<br><br> public ArrayList(Collection<? extends E> c) {    elementData = c.toArray();  //返回包含此 collection 中所有元素的數組  size = elementData.length;  // c.toArray might (incorrectly) not return Object[] (see 6260652)  if (elementData.getClass() != Object[].class)   elementData = Arrays.copyOf(elementData, size, Object[].class); //複製指定的數組,返回包含相同元素和長度的Object類型的數組 }

當採用不帶參數的構造方法ArrayList()產生一個集合對象時,其實是在底層調用ArrayList(int initialCapacity)這一構造方法生產一個長度為10的Object類型的數組。當採用帶有集合型別參數的構造方法時,在底層產生一個包含相同的元素和長度的Object類型的數組。 

2、add方法:ArrayList提供了兩種添加元素的add方法
1) add(E e),將指定的元素添加到此列表的尾部。
2) add(int index, E e),將指定的元素插入此列表中的指定位置。向右移動當前位於該位置的元素(如果有)以及所有後續元素(將其索引加 1)private int size;

public boolean add(E e) {  ensureCapacity(size + 1); // 擴大數組容量  elementData[size++] = e;  //將元素e添加到下標為size的Object數組中,並且執行size++  return true;  }  public void add(int index, E element) {  if (index > size || index < 0) //如果指定要插入的數組下標超過數組容量或者指定的下標小於0,拋異常    throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);   ensureCapacity(size+1); // 擴大數組容量  System.arraycopy(elementData, index, elementData, index + 1,size - index); //從指定源數組中複製一個數組,複製從指定的位置開始,到目標數組的指定位置結束。<br>                                          // elementData --- 源數組  index --- 源數組中的起始位置  <br>                                          // elementData --- 目標數組 index+1 --- 目標數組中的起始位置<br>                                          // size - index --- 要複製的數組元素的數量  elementData[index] = element; //將要添加的元素放到指定的數組下標處  size++;  }
public void ensureCapacity(int minCapacity) {  modCount++;  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); //複製指定的數組,返回新數組的容量為newCapacity  }  }

如果集合中添加的元素超過了10個,那麼ArrayList底層會新產生一個數組,長度為原數組的1.5倍+1,並將原數組中的元素copy到新數組中,並且後續添加的元素都會放在新數組中,當新數組的長度無法容納新添加的元素時,重複該過程。這就是集合添加元素的實現原理。

3、get方法:
 1) get(int index),返回此列表中指定位置上的元素。

public E get(int index) {  RangeCheck(index); //檢查傳入的指定下標是否合法   return (E) elementData[index]; //返回數組下標為index的數組元素  }private void RangeCheck(int index) {  if (index >= size) //如果傳入的下標大於或等於集合的容量,拋異常    throw new IndexOutOfBoundsException(    "Index: "+index+", Size: "+size);  }

4、remove方法:
1) E remove(int index),移除此列表中指定位置上的元素。向左移動所有後續元素(將其索引減 1)。
2) boolean remove(Object o),移除此列表中首次出現的指定元素(如果存在)。如果列表不包含此元素,則列表不做改動,返回boolean值。 

public E remove(int index) {  RangeCheck(index); //檢查指定的下標是否合法   modCount++;  E oldValue = (E) elementData[index]; //擷取指定下標的數組元素   int numMoved = size - index - 1; //要移動的元素個數  if (numMoved > 0)    System.arraycopy(elementData, index+1, elementData, index, numMoved); //移動數組元素  elementData[--size] = null; // Let gc do its work   return oldValue;  }  public boolean remove(Object o) {  if (o == null) { //如果傳入的參數為null      for (int index = 0; index < size; index++)    if (elementData[index] == null) { //移除首次出現的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) { //移除指定位置的元素,實現方法類似remove(int i)    modCount++;    int numMoved = size - index - 1;    if (numMoved > 0)      System.arraycopy(elementData, index+1, elementData, index,               numMoved);    elementData[--size] = null; // Let gc do its work  }

5、clone方法:
1) Object clone(),返回此ArrayList執行個體的淺表副本(不複製這些元素本身) 。

public Object clone() {  try {    ArrayList<E> v = (ArrayList<E>) super.clone(); //調用Object類的clone方法返回一個ArrayList對象    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();  }  }

以上通過對ArrayList部分關鍵源碼的分析,知道了ArrayList底層的實現原理,關於ArrayList源碼有以下幾點幾點總結:
 1) ArrayList 底層是基於數組來實現的,可以通過下標準確的找到目標元素,因此尋找的效率高;但是添加或刪除元素會涉及到大量元素的位置移動,效率低。
 2) ArrayList提供了三種不同的構造方法,無參數的構造方法預設在底層產生一個長度為10的Object類型的數組,當集合中添加的元素個數大於10,數組會自動進行擴容,即產生一個新的數組,並將原數組的元素放到新數組中。
3) ensureCapacity方法對數組進行擴容,它會產生一個新數組,長度是原數組的1.5倍+1,隨著向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.