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

Java ArrayList擴(kuò)容機(jī)制原理深入分析

 更新時(shí)間:2023年02月22日 11:35:51   作者:綠仔牛奶_  
在Java中,ArrayList是最常用的集合之一。它是一種容器,它的內(nèi)部定義了一個(gè)Object類(lèi)型的數(shù)組elementData,因此可用于存儲(chǔ)任意類(lèi)型的數(shù)據(jù)。我們知道,數(shù)組是長(zhǎng)度恒定的。而ArrayList相當(dāng)于是一個(gè)長(zhǎng)度可變的動(dòng)態(tài)數(shù)組,一起來(lái)看看的它的擴(kuò)容機(jī)制

擴(kuò)容機(jī)制

ArrayList是一個(gè)底層基于數(shù)組實(shí)現(xiàn)的集合容器。當(dāng)我們?cè)趧?chuàng)建ArrayList對(duì)象時(shí),默認(rèn)數(shù)組長(zhǎng)度為10,當(dāng)然也可以在創(chuàng)建時(shí)指定長(zhǎng)度。之后在程序執(zhí)行過(guò)程中,不斷地向ArrayList中添加數(shù)據(jù)。當(dāng)數(shù)據(jù)存儲(chǔ)達(dá)到底層數(shù)組最大容量時(shí)則會(huì)觸發(fā)擴(kuò)容機(jī)制

擴(kuò)容原理

首先創(chuàng)建一個(gè)新的數(shù)組,新數(shù)組的長(zhǎng)度時(shí)原數(shù)組的1.5倍。然后調(diào)用Arrays.copyOf()方法將原數(shù)組的所有數(shù)據(jù)copy到新數(shù)組中,再將當(dāng)前新添加的數(shù)據(jù)添加至新數(shù)組并返回

源碼分析

先來(lái)看ArrayList類(lèi)生命的幾個(gè)參數(shù)

// 默認(rèn)ArrayList底層數(shù)組長(zhǎng)度為10
private static final int DEFAULT_CAPACITY = 10;
// 空數(shù)組  其他地方調(diào)用
private static final Object[] EMPTY_ELEMENTDATA = {};
// 默認(rèn)長(zhǎng)度的空數(shù)組
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// elementData 真正存儲(chǔ)數(shù)據(jù)的數(shù)組  ArrayList的容量就是該數(shù)組的長(zhǎng)度 
// 默認(rèn)創(chuàng)建空的ArrayList將在第一次調(diào)用add方法時(shí)將該數(shù)組擴(kuò)容成為DEFAULT_CAPACITY = 10的容量
transient Object[] elementData;
// size代表的是當(dāng)前elementData數(shù)組中存儲(chǔ)的元素個(gè)數(shù)  并不是數(shù)組的容量! 
private int size;

當(dāng)我們創(chuàng)建ArrayList對(duì)象并且指定長(zhǎng)度時(shí)調(diào)用的構(gòu)造器

ArrayList<> list = new ArrayList<>(12);
public ArrayList(int initialCapacity) {
    // initialCapacity就是你指定的長(zhǎng)度
    // 邏輯判斷
        if (initialCapacity > 0) {
// initialCapacity符合要求就創(chuàng)建新數(shù)組 長(zhǎng)度為你指定的長(zhǎng)度
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
// 如果initialCapacity為0則得到一個(gè)空數(shù)組
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
        }
    }

不指定長(zhǎng)度時(shí)構(gòu)造器

public ArrayList() {
    // 使用默認(rèn)長(zhǎng)度大小的數(shù)組
  this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

需要注意的是,我們不論用上述哪個(gè)構(gòu)造器,首先第一步創(chuàng)建出來(lái)的都是空數(shù)組,但是會(huì)在第一次添加數(shù)據(jù)的時(shí)候執(zhí)行不同方法進(jìn)行擴(kuò)容

下面我們從調(diào)用add()方法開(kāi)始分析:

每次添加數(shù)據(jù)都會(huì)將size+1去進(jìn)行判斷,保證數(shù)組擁有至少存儲(chǔ)這個(gè)新數(shù)據(jù)的空間

public boolean add(E e) {
    // 就此處開(kāi)始一系列的擴(kuò)容判斷和操作
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;// 添加數(shù)據(jù)
        return true;
    }
// 下面是add方法中第一行執(zhí)行的方法  此處minCapacity就是數(shù)組的最小容量  也就是當(dāng)前存儲(chǔ)的元素個(gè)數(shù)+1
private void ensureCapacityInternal(int minCapacity) {
 ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

CalculateCapacity()方法用于判斷當(dāng)前數(shù)組是否是默認(rèn)容量的數(shù)組,如果是默認(rèn)容量的數(shù)組那么此時(shí)就要確定是否是第一次添加數(shù)據(jù)

如果是第一次添加數(shù)據(jù),那么就將返回DEFAULT_CAPACITY=10也就是minCapacity=10

如果不是第一次添加數(shù)據(jù),就將添加新數(shù)據(jù)之后的最小容量返回

其次還要注意的是,如果在創(chuàng)建ArrayList對(duì)象時(shí)使用的指定長(zhǎng)度的構(gòu)造器那么就會(huì)直接返回最小容量,也就是說(shuō)如果你創(chuàng)建ArrayList指定長(zhǎng)度為0,那么此時(shí)就會(huì)返回minCapacity=1,指定長(zhǎng)度為0這個(gè)清空后面給到具體分析

private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

ensureExplicitCapacity()方法用于判斷是否需要擴(kuò)容,經(jīng)過(guò)上述方法將最小容量minCapacity傳入ensureExplicitCapacity方法,如果這個(gè)所需最小容量大于當(dāng)前數(shù)組容量(也就是當(dāng)前數(shù)組存不下這個(gè)新數(shù)據(jù)了)則觸發(fā)擴(kuò)容機(jī)制grow()方法,反之不會(huì)進(jìn)行擴(kuò)容

private void ensureExplicitCapacity(int minCapacity) {
        modCount++;// modCount++是做什么的? 我也不知道
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

在分析grow()方法之前我們先明確兩個(gè)概念:

ArrayList定義了允許存儲(chǔ)的最大容量也就是Integer允許的范圍-8,如果溢出則是負(fù)數(shù)

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

Integer類(lèi)型的范圍是: -2的31次方~2的31次方減1

@Native public static final int MAX_VALUE = 0x7fffffff;

下面我們來(lái)看真正實(shí)現(xiàn)擴(kuò)容的grow()方法

private void grow(int minCapacity) {
        // overflow-conscious code
    // 獲取原數(shù)組容量
        int oldCapacity = elementData.length;
    // 新數(shù)組的容量是原數(shù)組容量的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 判斷新數(shù)組容量是否小于最小容量
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
    // 判斷新容量是否超過(guò)了ArrayList允許的最大值
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
    // 調(diào)用copyOf方法將原數(shù)據(jù)全部復(fù)制到新的空數(shù)組中
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
// 超出了ArrayList容量執(zhí)行hugeCapacity
    private static int hugeCapacity(int minCapacity) {
        // 因?yàn)镮nteger溢出則為負(fù)數(shù),此處判斷是否溢出
        if (minCapacity < 0) // overflow
            // 拋出異常  內(nèi)存溢出
            throw new OutOfMemoryError();
        // 沒(méi)有溢出則判斷最小容量是否大于了ArrayList允許的最大值
        // 大于--> 返回Integer最大值
        // 小于--> 返回ArrayList允許的最大值
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

值得注意的是,如果當(dāng)前數(shù)組是無(wú)參構(gòu)造器默認(rèn)生成的空數(shù)組,并且是第一次添加數(shù)據(jù)時(shí),那么數(shù)組的長(zhǎng)度將會(huì)直接變?yōu)?0

如果當(dāng)前的數(shù)組是有參構(gòu)造器(指定長(zhǎng)度)生成并且指定初始容量為0,那么在前四次調(diào)用add方法添加數(shù)據(jù)時(shí)每次擴(kuò)容都是+1,只有在第五次才會(huì)執(zhí)行1.5倍擴(kuò)容。

因?yàn)榈谝淮翁砑觿t是minCapacity=1,oldCapacity=0 執(zhí)行int newCapacity = oldCapacity + (oldCapacity >> 1);之后newCapacity 還是0,則執(zhí)行if (newCapacity - minCapacity < 0) -->newCapacity = minCapacity;也就是1,那么newCapacity 就為1,后面的三次以此類(lèi)推差不多

那么至此,ArrayList就完成了擴(kuò)容

到此這篇關(guān)于Java ArrayList擴(kuò)容機(jī)制原理深入分析的文章就介紹到這了,更多相關(guān)Java ArrayList擴(kuò)容機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot整合Mybatis與thymleft實(shí)現(xiàn)增刪改查功能詳解

    SpringBoot整合Mybatis與thymleft實(shí)現(xiàn)增刪改查功能詳解

    MybatisPlus是國(guó)產(chǎn)的第三方插件,?它封裝了許多常用的CURDapi,免去了我們寫(xiě)mapper.xml的重復(fù)勞動(dòng)。本文將整合MybatisPlus實(shí)現(xiàn)增刪改查功能,感興趣的可以了解一下
    2022-12-12
  • Spring之什么是ObjectFactory?什么是ObjectProvider?

    Spring之什么是ObjectFactory?什么是ObjectProvider?

    這篇文章主要介紹了Spring之什么是ObjectFactory?什么是ObjectProvider?具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • Java之jpa入門(mén)教程講解

    Java之jpa入門(mén)教程講解

    這篇文章主要介紹了Java之jpa入門(mén)教程講解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Java 使用openoffice進(jìn)行word轉(zhuǎn)換為pdf的方法步驟

    Java 使用openoffice進(jìn)行word轉(zhuǎn)換為pdf的方法步驟

    這篇文章主要介紹了Java 使用openoffice進(jìn)行word轉(zhuǎn)換為pdf的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • 一篇文章帶你入門(mén)java集合

    一篇文章帶你入門(mén)java集合

    Java的集合類(lèi)型都是對(duì)java.util包中Collection接口的繼承,這里我們主要介紹依賴于collection的一些主分支,一起來(lái)看一下Java中的collection集合類(lèi)型總結(jié)
    2021-08-08
  • Spingboot?JPA?CriteriaBuilder?如何獲取指定字段

    Spingboot?JPA?CriteriaBuilder?如何獲取指定字段

    這篇文章?主要介紹了Spingboot?JPA?CriteriaBuilder?如何獲取指定字段,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • SpringMVC的注解@RequestMapping屬性及使用

    SpringMVC的注解@RequestMapping屬性及使用

    這篇文章主要為大家介紹了SpringMVC注解@RequestMapping屬性及使用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Java微信二次開(kāi)發(fā)(二) Java微信文本消息接口請(qǐng)求與發(fā)送

    Java微信二次開(kāi)發(fā)(二) Java微信文本消息接口請(qǐng)求與發(fā)送

    這篇文章主要為大家詳細(xì)介紹了Java微信二次開(kāi)發(fā)第二篇,Java微信文本消息接口請(qǐng)求與發(fā)送功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • Redis?+?Java攔截器實(shí)現(xiàn)用戶匿名和非匿名訪問(wèn)

    Redis?+?Java攔截器實(shí)現(xiàn)用戶匿名和非匿名訪問(wèn)

    本文主要介紹了Redis?+?Java攔截器實(shí)現(xiàn)用戶匿名和非匿名訪問(wèn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • SpringBoot整合Servlet和Filter和Listener組件詳解

    SpringBoot整合Servlet和Filter和Listener組件詳解

    這篇文章主要介紹了SpringBoot整合Servlet和Filter和Listener組件詳解,在整合某報(bào)表插件時(shí)就需要使用Servlet,Spring Boot中對(duì)于整合這些基本的Web組件也提供了很好的支持,需要的朋友可以參考下
    2024-01-01

最新評(píng)論