jdk源碼之ArrayList

概要

  • 類繼承關(guān)系

java.lang.Object
java.util.AbstractCollection<E>
java.util.AbstractList<E>
java.util.ArrayList<E>

  • 定義

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
}

實現(xiàn)

  • 創(chuàng)建
public ArrayList() {    
  this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

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);    
  }
}

由代碼可知,ArrayList采用數(shù)組方式存放對象。無參構(gòu)造器創(chuàng)建一個空Object數(shù)組

private static final Object[] EMPTY_ELEMENTDATA = {};

  • 插入:add(E)
    add方法其實就是給數(shù)組中某元素賦值為傳入的對象,但add時有個明顯的問題是,數(shù)組滿了怎么辦?我們接著往下看。
public boolean add(E e) {    
  ensureCapacityInternal(size + 1);  // Increments modCount!!    
  elementData[size++] = e;    
  return true;
}

ensureCapacityInternal函數(shù)的作用是保證數(shù)組大小是夠用的。

private void ensureCapacityInternal(int minCapacity) {    
  if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {        
    minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);    
  }    
  ensureExplicitCapacity(minCapacity);
}

參數(shù)傳入數(shù)組的size + 1, 如果數(shù)組為空數(shù)組,則將minCapacity設(shè)為10或者minCapacity中的大值

private static final int DEFAULT_CAPACITY = 10;

函數(shù)ensureExplicitCapacity用來產(chǎn)生明確的容量, 如果minCapacity大于數(shù)組大小,則進行擴容。

private void ensureExplicitCapacity(int minCapacity) {    
  modCount++;    

  // overflow-conscious code    
  if (minCapacity - elementData.length > 0)        
    grow(minCapacity);
}

擴容代碼如下:

private void grow(int minCapacity) {    
  // overflow-conscious code    
  int oldCapacity = elementData.length;    
  int newCapacity = oldCapacity + (oldCapacity >> 1);    
  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;
}

首先產(chǎn)生新的數(shù)組大小為原來的1.5倍,若新的容量仍小于minCapacity,則minCapacity為新的容量,得出新的容量值后,調(diào)用Arrays.copyOf來生成新的數(shù)組對象,如想調(diào)整容量的生長策略,可繼承ArrayList, 并覆寫ensureCapacity方法。

在Collection中增加對象時,ArrayList還提供add(int, E)這樣的方法,允許將元素直接插入到int位置。它要將當(dāng)前數(shù)組的對象進行一次復(fù)制,即將目前index及其后的數(shù)據(jù)都往后挪一位,該方式要多一次復(fù)制數(shù)組的代價。

public void add(int index, E element) {    
  rangeCheckForAdd(index);    
  ensureCapacityInternal(size + 1);  // Increments modCount!!    
  System.arraycopy(elementData, index, elementData, index + 1, size - index);    
  elementData[index] = element;    size++;
}
  • 刪除:remove(E)
    先上代碼:
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;
}

如果要刪除的對象為null, 循環(huán)遍歷整個數(shù)組,找到為null值的元素,調(diào)用fastRemove刪除相應(yīng)位置的對象。

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
}

又代碼可知,fastRemove是一次數(shù)組的復(fù)制,將index后的對象統(tǒng)一向前移動一位,將最后一位設(shè)為null, 釋放此對象的引用。

若對象非null, 則通過equals來進行比較,同樣通過fastRemove來刪除元素。

  • 獲取單個對象:get(int)
public E get(int index) {    
  rangeCheck(index);    
  return elementData(index);
}

先做數(shù)組范圍檢查,在返回對象。

  • 遍歷對象:iterator
public Iterator<E> iterator() {    return new Itr();}

每次調(diào)用iterator方法時,都會new一個Itr的實例。
當(dāng)調(diào)用此實例的hasNext方法時,比較當(dāng)前指向的數(shù)組的位置是否和數(shù)組中已有元素大小相等,如相等返回false,否則返回true。
、、、
public boolean hasNext() {
return cursor != size; // cursor標識下一個返回元素的位置
}
、、、

當(dāng)調(diào)用實例的next方法時,首先比較在創(chuàng)建此Iterator時獲取的modCount與當(dāng)前的modCount,如果不等,則說明在獲取next元素時,發(fā)生了對集合大小產(chǎn)生影響(新增、刪除)的動作。當(dāng)發(fā)生這種情況時,則拋出ConcurrentModificationException。

  • 判斷對象時候存在:contains(E)
public boolean contains(Object o) {    return indexOf(o) >= 0;}

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;
}

如果E為null,則直接判斷已有元素是否為null, 否則通過判斷E.equals和元素是否相等。

  • transient
transient Object[] elementData; // non-private to simplify nested class access

聲明為transient后,這個字段不會被序列化。

  • SuppressWarnings
@SuppressWarnings("unchecked")

告訴編譯器,對特定類型的warning保持沉默。

注:

  1. ArrayList基于數(shù)組實現(xiàn),無容量的限制。
  2. ArrayList插入元素時可能要擴容,刪除時并不會減小數(shù)組的容量。
  3. 若希望縮小數(shù)組容量,可以調(diào)用ArrayList的trimToSize()
public void trimToSize() {    
  modCount++;    
    if (size < elementData.length) {        
      elementData = (size == 0)          
        ? EMPTY_ELEMENTDATA          : Arrays.copyOf(elementData, size);    
    }
}
  1. ArrayList非線程安全。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容