欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

新手入門了解ArrayList擴容機制

 更新時間:2020年10月27日 16:40:10   作者:愛編程DE文兄  
這篇文章主要介紹了新手入門了解ArrayList擴容機制,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下

我們下面用最簡單的代碼創(chuàng)建ArrayList并添加11個元素,并 一 一 講解底層源碼;在說之前,給大家先普及一些小知識:

  》ArrayList底層是用數(shù)組來實現(xiàn)的

  》數(shù)組一旦創(chuàng)建后,大小就是固定的,如果超出了數(shù)組大小后,就會創(chuàng)建一個新的數(shù)組

  》接下來所謂數(shù)組的擴容實質上是重新創(chuàng)建一個大小更大的新數(shù)組

@Test
  public void testArrayList() {
    //創(chuàng)建一個泛型為String的ArrayList(這里泛型是什么不重要)
    ArrayList<String> list = new ArrayList<String>();
    //依次添加11個元素
    list.add("1");
    list.add("2");
    list.add("3");
    list.add("4");
    list.add("5");
    list.add("6");
    list.add("7");
    list.add("8");
    list.add("9");
    list.add("10");
    list.add("11");
  }

上面的代碼中,我們就只調用了add(),在看add()源碼前,我必須給你們先介紹一些在ArrayList的常量和變量,因為在接下來的源碼中會涉及到這些,怕你們到時一臉蒙

private static final int DEFAULT_CAPACITY = 10;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
transient Object[] elementData;
private int size;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

  》DEFAULT_CAPACITY:default_capcity,默認的容量大小,也就是當你第一次創(chuàng)建數(shù)組并往里面添加第一個元素時,數(shù)組的默認容量大小

  》DEFAULTCAPACITY_EMPTY_ELEMENTDATA:defaultcapacity_empty_elementdata是默認的空數(shù)組,他的作用是當elementData為{},即空數(shù)組時,把它賦值給elementData,要是理解不了,請你往下繼續(xù)看!

  》elementData:表示的就是當前存儲元素的數(shù)組

  》size:他表示當前還沒有添加新元素前的數(shù)組中有效的元素個數(shù),比如說數(shù)組長度為10,只保存了5個元素,那有效長度就是5

  》MAX_ARRAY_SIZE:最大數(shù)組長度,它用來標識當前數(shù)組可保存元素的最大長度,值為Integer_MAX_VALUE -8,即2147483647 - 8 ,這里的 8 代表8字節(jié)用來保存數(shù)組本身的內(nèi)存大小。

現(xiàn)在我們進入到add()里面看他們具體如何實現(xiàn)的,如下代碼:

public boolean add(E e) {
    
    ensureCapacityInternal(size + 1); // Increments modCount!!
    elementData[size++] = e;
    return true;
  }

  》ensureCapacityInternal(size + 1):這個方法意為“確保內(nèi)部變量”,什么意思呢?他是用來判斷當前數(shù)組的容量是否足夠,不足就擴容;等下我們會進入這個方法來看他如何具體實現(xiàn)的,size表示當前還未添加新元素前的數(shù)組有效元素個數(shù),而size+1表示傳入當前數(shù)組的最小容量(有效長度)
  》elementData[size++] = e:這段語句意思是給數(shù)組做賦值操作,簡單說就是給數(shù)組添加元素;比如說當前數(shù)組已經(jīng)有3個元素了,那現(xiàn)在再添加一個元素a,則這一步為elementData[3]=a;

  》return true:代表添加成功;

現(xiàn)在我們就進入到ensureCapacityInternal(),如下代碼:

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
  }

這里面涉及兩個方法ensureExplicitCapacity()和calculateCapacity():

  》calculateCapacity():計算容量,它用來計算當前的數(shù)組所需的最小容量minCapacity, 你可以理解為當前數(shù)組的有效長度;源碼如下:

private static int calculateCapacity(Object[] elementData, int minCapacity) {    //若傳入的是個空數(shù)組,則返回的是最小容量 是 默認容量(10) 和 當前最小容量(0)之間的最大值
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
      return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
  }

PS:第一次添加元素時calculateCapacity返回的最小容量minCapacity是10,從第二次開始minCapacity為2,第三次為3,依次類推..在這里第一次返回10大家不要糾結它的意義,重點在第二次及之后表示的意思

  》ensureExplicitCapacity():判斷是否需要擴容;查看它的源碼:

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

    // overflow-conscious code當最小容量大于當前的數(shù)組大小時
    if (minCapacity - elementData.length > 0)      //計算擴容后的數(shù)組大小
      grow(minCapacity);
  }

我們第一次list.add(),最小容量minCapacity是10,elementData.length長度為0,所以條件成立,進入grow()(第二次minCapacity是2,elementData.length為10,條件不成立就不再擴容了;當?shù)?1次時,11>10,又可以擴容了)

private void grow(int minCapacity) {
    // 得到當前數(shù)組的大小,即老數(shù)組大小
    int oldCapacity = elementData.length;
    //將舊數(shù)組大小+舊數(shù)組/2,即舊數(shù)組的1.5倍是新數(shù)組的大?。ㄏ炔灰谝?gt;>1的意思,你只要知道oldCapacity >> 1表示oldCapacity/2就行)
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    //如果擴容后的是數(shù)組大小還是小于最小所需容量,直接讓minCapacity賦值到新容量
    if (newCapacity - minCapacity < 0)
      newCapacity = minCapacity;
    //若新容量大小大于數(shù)組長度的最大預設值;由于擴容后是原數(shù)組的1.5倍,則非常有可能會溢出這個預設值
    if (newCapacity - MAX_ARRAY_SIZE > 0)
      newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    //上面都是為了確定最終的新容量的大小,這個方法是真正的擴容實現(xiàn)
    elementData = Arrays.copyOf(elementData, newCapacity);
  }

相信大家這上面大部分都能夠理解,可能就一個地方不太清楚:當newCapacity > MAX_ARRAY_SIZE(新容量大于預設值較特殊的情況,一般數(shù)組長度不會擴容到這么大)時調用hugeCapacity有啥用?我們看下hugeCapacity()的源碼:

private static int hugeCapacity(int minCapacity) {
    //若最小容量小于0的情況,拋出異常
    if (minCapacity < 0) // overflow
      throw new OutOfMemoryError();
    //若最小容量>最大預設值,返回Integer.Max_VALUE,否則是MAX_ARRAY_SIZE(Integer.Max_VALUE-8)
    return (minCapacity > MAX_ARRAY_SIZE) ?
      Integer.MAX_VALUE :
      MAX_ARRAY_SIZE;
  }

hugeCapacity()是用來限制新容量的大小的,是不能超出Integer.MAX_VALUE值的,最后說一點,數(shù)組的最大長度并不是MAX_ARRAY_SIZE,而是Integer.MAX_VALUE。

  》Arrays.copyOf(elementData, newCapacity),就不看源碼了,簡單說一下:它這個方法能返回一個擴容后的數(shù)組,將舊數(shù)組elementData的數(shù)據(jù)復制到長度為newCapacity的新數(shù)組中。

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • java.lang.IllegalStateException異常原因和解決辦法

    java.lang.IllegalStateException異常原因和解決辦法

    這篇文章主要給大家介紹了關于java.lang.IllegalStateException異常原因和解決辦法,IllegalStateException是Java標準庫中的一個異常類,通常表示在不合適或無效的情況下執(zhí)行了某個方法或操作,需要的朋友可以參考下
    2023-07-07
  • IDEA部署Docker鏡像的實現(xiàn)示例

    IDEA部署Docker鏡像的實現(xiàn)示例

    本文主要介紹了IDEA部署Docker鏡像的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-04-04
  • SpringBoot升級3.2報錯Invalid value type for attribute ‘factoryBeanObjectType‘: java.lang.String的解決方案

    SpringBoot升級3.2報錯Invalid value type for 

    這篇文章給大家介紹了SpringBoot升級3.2報錯Invalid value type for attribute ‘factoryBeanObjectType‘: java.lang.String的解決方案,文中有詳細的原因分析,需要的朋友可以參考下
    2023-12-12
  • 解決Unable to start embedded container SpringBoot啟動報錯問題

    解決Unable to start embedded container&nbs

    這篇文章主要介紹了解決Unable to start embedded container SpringBoot啟動報錯問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • SpringBoot實現(xiàn)任意位置獲取HttpServletRequest對象

    SpringBoot實現(xiàn)任意位置獲取HttpServletRequest對象

    這篇文章主要介紹了SpringBoot實現(xiàn)任意位置獲取HttpServletRequest對象,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • java 抽象類與接口的區(qū)別總結

    java 抽象類與接口的區(qū)別總結

    這篇文章主要介紹了java 抽象類與接口的區(qū)別總結的相關資料,需要的朋友可以參考下
    2017-02-02
  • 如何解決mybatis查詢結果接收不同的問題

    如何解決mybatis查詢結果接收不同的問題

    這篇文章主要介紹了如何解決mybatis查詢結果接收不同的問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-09-09
  • Java 中比較對象的用法小結

    Java 中比較對象的用法小結

    在 Java 中,比較對象的方法有多種多樣,每種都有其適用的場景,通過深入理解 equals() 方法、Comparable 接口和 Comparator 接口,我們能夠更好地處理對象之間的比較,使代碼更加靈活、清晰和健壯,本文給大家介紹Java 中比較對象的用法,感興趣的朋友一起看看吧
    2023-12-12
  • 詳解java中的static關鍵字

    詳解java中的static關鍵字

    這篇文章主要介紹了java中的static關鍵字的的相關資料,文中講解非常細致,代碼幫助大家更好的理解和學習,感興趣的朋友可以了解下
    2020-06-06
  • MybatisPlus為何可以不用@MapperScan詳解

    MybatisPlus為何可以不用@MapperScan詳解

    這篇文章主要給大家介紹了關于MybatisPlus為何可以不用@MapperScan的相關資料,文中通過圖文介紹的非常詳細,對大家學習或者使用MybatisPlus具有一定的參考學習價值,需要的朋友可以參考下
    2023-04-04

最新評論