溫馨提示×

溫馨提示×

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

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

怎么用add方法理解ArrayList的擴容機制

發布時間:2023-03-07 10:01:38 來源:億速云 閱讀:428 作者:iii 欄目:開發技術

這篇文章主要介紹“怎么用add方法理解ArrayList的擴容機制”,在日常操作中,相信很多人在怎么用add方法理解ArrayList的擴容機制問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么用add方法理解ArrayList的擴容機制”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

ArrayList的構造方法(前置知識)

可快速過

一些基本成員變量:

// 默認初始大小
private static final int DEFAULT_CAPACITY = 10;
// 空數組 用于空實例
private static final Object[] EMPTY_ELEMENTDATA = new Object[0];
// 用于默認大小空實例的共享空數組實例。
// 我們把它從EMPTY_ELEMENTDATA數組中區分出來,以知道在添加第一個元素時容量需要增加多少。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
// 保存ArrayList數據的數組
transient Object[] elementData;
// 大小
private int size;
// 數組的最大長度
private static final int MAX_ARRAY_SIZE = 2147483639;

構造方法:

   /**
     * 默認初始容量大小
     */
    private static final int DEFAULT_CAPACITY = 10;
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    /**
     *默認構造函數,使用初始容量10構造一個空列表(無參數構造)
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    /**
     * 帶初始容量參數的構造函數。(用戶自己指定容量)
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {//初始容量大于0
            //創建initialCapacity大小的數組
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {//初始容量等于0
            //創建空數組
            this.elementData = EMPTY_ELEMENTDATA;
        } else {//初始容量小于0,拋出異常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
   /**
    *構造包含指定collection元素的列表,這些元素利用該集合的迭代器按順序返回
    *如果指定的集合為null,throws NullPointerException。
    */
     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;
        }
    }

ArrayList的add方法(理解擴容機制)

add 添加元素

    /**
     * 將指定的元素追加到此列表的末尾。
     */
    public boolean add(E e) {
        // 添加元素之前,先試探,容量夠不夠
        // Increments modCount!! 這里有個failfast機制
        // 簡而言之就是并發場景下通過modcount的值判斷當前的操作是否是最新的modcount的數據
        ensureCapacityInternal(size + 1);  
        //這里看到ArrayList添加元素的實質就相當于為數組賦值
        elementData[size++] = e;
        return true;
    }

得到最小擴容量

我們接下來看看這個“試探容量的方法”ensureCapacityInternal()怎么實現的

我們約定一個值,也就是傳參進來的size+1,叫minCapacity(最小需要容量)

   //得到最小擴容量    就是你至少要擴容至這么多,才能容納下我的數據
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
              // 獲取默認的容量和傳入參數的較大值
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }

當要add進第1個元素時,minCapacity為1,在Math.max()方法比較后,minCapacity為10。

判斷是否需要擴容

然后是ensureExplicitCapacity():

  //判斷是否需要擴容
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            //調用grow方法進行擴容,調用此方法代表已經開始擴容了
            grow(minCapacity);
    }

我們來梳理一下:

  • 當我們要 add 進第 1 個元素到 ArrayList 時,elementData.length為0 (因為還是一個空的 list),因為執行了 ensureCapacityInternal() 方法 ,所以minCapacity此時為 10。此時,minCapacity - elementData.length > 0成立,所以會進入 grow(minCapacity) 方法,此時數組容量變為10

  • 當 add 第 2 個元素時,minCapacity 為 2,此時 elementData.length(容量)在添加第一個元素后擴容成 10 了。此時,minCapacity - elementData.length > 0 不成立,所以不會進入 (執行)grow(minCapacity) 方法。

  • 添加第 3、4&middot;&middot;&middot;到第10個元素時,依然不會執行 grow()方法,數組容量都為10。

  • 直到添加第 11 個元素,minCapacity(為 11)比 elementData.length(為 10)要大。進入 grow 方法進行擴容。

擴容方法

按照elementData.length(newCapacity)擴容1.5倍,然后看看夠不夠minCapacity。

不夠的話,newCapacity就=minCapacity

hugeCapacity()比較一下newCapacity是否超過MAX_ARRAY_SIZE,超過就賦為Integer.MAX_VALUE

然后就進行擴容,Arrays.copyof方法

    /**
     * 要分配的最大數組大小
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    /**
     * ArrayList擴容的核心方法。
     */
    private void grow(int minCapacity) {
        // oldCapacity為舊容量,newCapacity為新容量
        int oldCapacity = elementData.length;
        //將oldCapacity 右移一位,其效果相當于oldCapacity /2,
        //我們知道位運算的速度遠遠快于整除運算,整句運算式的結果就是將新容量更新為舊容量的1.5倍,
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //然后檢查新容量是否大于最小需要容量,若還是小于最小需要容量,那么就把最小需要容量當作數組的新容量,
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
       // 如果新容量大于 MAX_ARRAY_SIZE,進入(執行) `hugeCapacity()` 方法來比較 minCapacity 和 MAX_ARRAY_SIZE,
       //如果minCapacity大于最大容量
       //則新容量則為`Integer.MAX_VALUE`,否則,新容量大小則為 MAX_ARRAY_SIZE 即為 `Integer.MAX_VALUE - 8`。
        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);
    }

int newCapacity = oldCapacity + (oldCapacity >> 1),所以 ArrayList 每次擴容之后容量都會變為原來的 1.5 倍左右(oldCapacity 為偶數就是 1.5 倍,否則是 1.5 倍左右)! 奇偶不同,比如 :10+10/2 = 15, 33+33/2=49。如果是奇數的話會丟掉小數

tips:

  • java 中的 length屬性是針對數組說的,比如說你聲明了一個數組,想知道這個數組的長度則用到了 length 這個屬性.

  • java 中的 length() 方法是針對字符串說的,如果想看這個字符串的長度則用到 length() 這個方法.

  • java 中的 size() 方法是針對泛型集合說的,如果想看這個泛型有多少個元素,就調用此方法來查看!

到此,關于“怎么用add方法理解ArrayList的擴容機制”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女