溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

java集合中ArrayList源碼解析是怎樣的

發(fā)布時間:2021-09-30 10:32:13 來源:億速云 閱讀:168 作者:柒染 欄目:大數(shù)據(jù)

今天就跟大家聊聊有關(guān)java集合中ArrayList源碼解析是怎樣的,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

整體架構(gòu)

ArrayList實際就是個數(shù)組結(jié)構(gòu),如圖

java集合中ArrayList源碼解析是怎樣的

index:數(shù)組下標(biāo)
elementData:數(shù)組本身

其他基本概念:

/**
 * Default initial capacity.
 * 數(shù)組初始大小
 */ 
private static final int DEFAULT_CAPACITY = 10;
/**
 * The size of the ArrayList (the number of elements it contains).
 * 當(dāng)前數(shù)組大小
 * @serial
 */
private int size;
//表示當(dāng)前數(shù)組被修改的版本次數(shù)
protected transient int modCount = 0;

類注釋:
1、可以自動擴(kuò)容
2、允許put null
3、size、set、put、add、get時間復(fù)雜度O(1)
4、非線程安全(作為共享變量時存在),必要時可以使用線程安全的SynchronizedList(性能低)

public boolean add(E e) {
    synchronized (mutex) {// synchronized 是一種輕量鎖,mutex 表示一個當(dāng)前 SynchronizedList
        return c.add(e);
    }
}

5、增強(qiáng)for循環(huán)或迭代時,若數(shù)組大小改變,則拋出異常

源碼解析

一、初始化:

//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、無參初始化 數(shù)組大小為空//初始化時數(shù)組大小不是默認(rèn)的10,第一次add時擴(kuò)容為10public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

//3、指定初始數(shù)據(jù)初始化public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

二、新增、擴(kuò)容、刪除

新增:

public boolean add(E e) {
  //確保數(shù)組大小是否足夠,不夠執(zhí)行擴(kuò)容,size 為當(dāng)前數(shù)組的大小
  ensureCapacityInternal(size + 1);  // Increments modCount!!
  //直接賦值,線程不安全的
  elementData[size++] = e; 對null無校驗,因此可以存入null值
  return true;
}

擴(kuò)容:

private void ensureCapacityInternal(int minCapacity) {
  //如果初始化數(shù)組大小時,有給定初始值,以給定的大小為準(zhǔn),不走 if 邏輯
  if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
    minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
  }
  //確保容積足夠
  ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
  //記錄數(shù)組被修改
  modCount++;
  // 如果我們期望的最小容量大于目前數(shù)組的長度,那么就擴(kuò)容
  if (minCapacity - elementData.length > 0)
    grow(minCapacity);
}
//擴(kuò)容,并把現(xiàn)有數(shù)據(jù)拷貝到新的數(shù)組里面去
private void grow(int minCapacity) {
  int oldCapacity = elementData.length;
  // oldCapacity >> 1 是把 oldCapacity 除以 2 的意思  這里注意:ArrayList擴(kuò)容是1+0.5倍
  int newCapacity = oldCapacity + (oldCapacity >> 1);

  // 如果擴(kuò)容后的值 < 我們的期望值,擴(kuò)容后的值就等于我們的期望值 
  if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;

  // 如果擴(kuò)容后的值 > jvm 所能分配的數(shù)組的最大值,那么就用 Integer 的最大值
  if (newCapacity - MAX_ARRAY_SIZE > 0)
    newCapacity = hugeCapacity(minCapacity);  擴(kuò)容時源碼中對上下數(shù)組大小做了校驗,有很清晰的數(shù)組大小溢出意識,平時開發(fā)時應(yīng)借鑒
  // 通過復(fù)制進(jìn)行擴(kuò)容
  elementData = Arrays.copyOf(elementData, newCapacity);
}

擴(kuò)容動態(tài)圖:

java集合中ArrayList源碼解析是怎樣的

刪除:

public boolean remove(Object o) {
  // 如果要刪除的值是 null,找到第一個值是 null 的刪除
  if (o == null) {
    for (int index = 0; index < size; index++)
      if (elementData[index] == null) { 可以刪除null值        fastRemove(index);
        return true;
      }
  } else {
    // 如果要刪除的值不為 null,找到第一個和要刪除的值相等的刪除
    for (int index = 0; index < size; index++)
      // 這里是根據(jù)  equals 來判斷值相等的,相等后再根據(jù)索引位置進(jìn)行刪除
      if (o.equals(elementData[index])) {  //找到需要刪除的索引        fastRemove(index);
        return true;
      }
  }
  return false;
}

//根據(jù)索引位置進(jìn)行元素刪除private void fastRemove(int index) {
  // 記錄數(shù)組的結(jié)構(gòu)要發(fā)生變動了
  modCount++;
  // numMoved 表示刪除 index 位置的元素后,需要從 index 后移動多少個元素到前面去
  // 減 1 的原因,是因為 size 從 1 開始算起,index 從 0開始算起
  int numMoved = size - index - 1;
  if (numMoved > 0)
    // 從 index +1 位置開始被拷貝,拷貝的起始位置是 index,長度是 numMoved
    System.arraycopy(elementData, index+1, elementData, index, numMoved);
  //數(shù)組最后一個位置賦值 null,幫助 GC
  elementData[--size] = null;
}

java集合中ArrayList源碼解析是怎樣的

三、迭代器

implement java.util.Iterator

迭代器的一些參數(shù):
int cursor;// 迭代過程中,下一個元素的位置,默認(rèn)從 0 開始。
int lastRet = -1; // 新增場景:表示上一次迭代過程中,索引的位置;刪除場景:為 -1。
int expectedModCount = modCount;// expectedModCount 表示迭代過程中,期望的版本號;modCount 表示數(shù)組實際的版本號。

迭代器源碼分析:

//是否存在下一個可迭代的值
public boolean hasNext() {
  return cursor != size;//cursor 表示下一個元素的位置,size 表示實際大小,如果兩者相等,說明已經(jīng)沒有元素可以迭代了,如果不等,說明還可以迭代
}

//下一個可迭代的值
public E next() {
  //迭代過程中,判斷版本號有無被修改,有被修改,拋 ConcurrentModificationException 異常
  checkForComodification();
  //本次迭代過程中,元素的索引位置
  int i = cursor;
  if (i >= size)
    throw new NoSuchElementException();
  Object[] elementData = ArrayList.this.elementData;
  if (i >= elementData.length)
    throw new ConcurrentModificationException();
  // 下一次迭代時,元素的位置,為下一次迭代做準(zhǔn)備
  cursor = i + 1;
  // 返回元素值
  return (E) elementData[lastRet = i];
}
// 版本號比較
final void checkForComodification() {
  if (modCount != expectedModCount)
    throw new ConcurrentModificationException();
}


public void remove() {
  // 如果上一次操作時,數(shù)組的位置已經(jīng)小于 0 了,說明數(shù)組已經(jīng)被刪除完了
  if (lastRet < 0)
    throw new IllegalStateException();
  //迭代過程中,判斷版本號有無被修改,有被修改,拋 ConcurrentModificationException 異常
  checkForComodification();

  try {
    ArrayList.this.remove(lastRet);
    cursor = lastRet;
    // -1 表示元素已經(jīng)被刪除,這里也防止重復(fù)刪除lastRet = -1;
    // 刪除元素時 modCount 的值已經(jīng)發(fā)生變化,在此賦值給 expectedModCount
    // 這樣下次迭代時,兩者的值是一致的了
    expectedModCount = modCount;
  } catch (IndexOutOfBoundsException ex) {
    throw new ConcurrentModificationException();
  }
}

看完上述內(nèi)容,你們對java集合中ArrayList源碼解析是怎樣的有進(jìn)一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI