最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的ArrayList容量及擴(kuò)容方式

 更新時(shí)間:2021年09月13日 17:01:02   作者:zx2015216856  
這篇文章主要介紹了Java中的ArrayList容量及擴(kuò)容方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

查看JDK1.8 ArrayList的源代碼

1、默認(rèn)初始容量為10

   /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;

2、最大容量為 Integer.MAX_VALUE - 8

    /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

原因:之前參考別人的,有待求證:

數(shù)組對(duì)象有一個(gè)額外的元數(shù)據(jù),用于表示數(shù)組的大??;

數(shù)組長(zhǎng)度size為int類型,共32位,有一位符號(hào)位,所以最大長(zhǎng)度為Integer.MAX_VALUE=2^31= 2,147,483,648;

8bytes用來(lái)存儲(chǔ)size;

3、擴(kuò)容方式:

(1)首先傳遞進(jìn)來(lái)一個(gè)希望的最小容量minCapacity;

(2)新容量newCapacity = oldCapacity + (oldCapacity >> 1),即新容量等于原容量的1.5倍;

(3)如果minCapacity > newCapacity ,newCapacity = minCapacity ;

(4)如果 newCapacity > 最大容量 MAX_ARRAY_SIZE ,newCapacity = hugeCapacity(minCapacity);

(5)以新容量拷貝原數(shù)據(jù)

   /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    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;
    }

Java ArrayList() 擴(kuò)容原理

平常都是直接使用 ArrayList(),今天特地看一下 ArrayList() 的擴(kuò)容原理。

先看下 ArrayList 的屬性以及構(gòu)造方法,這個(gè)比較重要

先看下屬性

// ArrayList 默認(rèn)容量大小
private static final int DEFAULT_CAPACITY = 10;
// 一個(gè)共享的空數(shù)組, 在空實(shí)例時(shí)使用
private static final Object[] EMPTY_ELEMENTDATA = {};
// 一個(gè)共享的空數(shù)組, 在使用默認(rèn) size 的空實(shí)例時(shí)使用
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/*
存儲(chǔ) ArrayList 元素的數(shù)組緩沖區(qū)
重點(diǎn)1: ArrayList 的容量是數(shù)組緩沖區(qū)的長(zhǎng)度
重點(diǎn)2: 從這個(gè)元素也可以看的出來(lái) ArrayList() 的底層就是一個(gè) Object[]  
add 第一個(gè)元素時(shí), 任何帶有 elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的空 ArrayList 都將被擴(kuò)展為 DEFAULT_CAPACITY
*/
transient Object[] elementData;
// ArrayList 的大小, 我們平常使用的 list.size() 底層就是記錄的這個(gè) size
private int size;
// ArrayList 最大
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

再看構(gòu)造器,帶參構(gòu)造器

/*
帶參構(gòu)造器, 參數(shù)為容量大小, 例如: 初始化一個(gè)容器為 20 類型為 Integer 的 ArrayList
ArrayList<Integer> list = new ArrayList<>(20);
*/
public ArrayList(int initialCapacity) {
 /*
 初始化容量 > 0, elementData 初始化為初始化容量大小的數(shù)組
 初始化容量 = 0, elementData = EMPTY_ELEMENTDATA (空數(shù)組)
 初始化容量 < 0, 直接拋出異常
 */
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

參數(shù)為 Collection 的構(gòu)造器

/*
將一個(gè)參數(shù)為 Collection 的集合轉(zhuǎn)換為 ArrayList
*/
public ArrayList(Collection<? extends E> c) {
    // Collection 轉(zhuǎn)換為數(shù)組 Object[] 類型 
    elementData = c.toArray();
    // 判斷當(dāng)前對(duì)象大小是否和 Collection 長(zhǎng)度相等并且不等于 0, false 的話 elementData 等于空數(shù)組了
    if ((size = elementData.length) != 0) {
     // c.toArray() 可能不會(huì)正確地返回一個(gè) Object[] 數(shù)組,所以使用 Arrays.copyOf()
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

不帶參構(gòu)造器

/*
不帶參構(gòu)造器就像我們平時(shí)使用一樣, 直接 new 一個(gè) ArrayList 不需要傳遞任何參數(shù)
構(gòu)造方法中直接將 elementData 初始化為 DEFAULTCAPACITY_EMPTY_ELEMENTDATA (空數(shù)組)
*/
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

看到這里就發(fā)現(xiàn),帶參的構(gòu)造器我們可以直接傳遞參數(shù),而默認(rèn)的構(gòu)造器怎么怎么樣初始化容量大小的呢?

add() 方法可以直接得到答案。

public boolean add(E e) {
 // 這一行是關(guān)鍵, 看下面
    ensureCapacityInternal(size + 1);
    // 將元素追加到集合的末尾 假如當(dāng)前 size = 10 size++ 追加到第 11 位
    elementData[size++] = e;
    return true;
}

ensureCapacityInternal() 方法調(diào)用

private void ensureCapacityInternal(int minCapacity) {
 /*
 calculateCapacity() 方法, 剛初始化時(shí)會(huì)返回 10, 其他情況返回當(dāng)前 size + 1
 ensureExplicitCapacity() 方法, 調(diào)用擴(kuò)容
 */
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) { 
 /*
 使用無(wú)參構(gòu)造器創(chuàng)建創(chuàng)建 ArrayList 的集合, 此時(shí)一定是相等的
 */
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
     /*
     兩數(shù)相比返回最大值, 此時(shí) Math.max(10, 1); 
     默認(rèn)容量, 由此而來(lái)
     */
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    // 不相等的話只有返回當(dāng)前的 size + 1
    return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
    // 增量, 記錄修改/更新次數(shù)
    modCount++;  
    
     // 初始化: 10 - 0 > 0
     // 其他: size + 1 > 0
    if (minCapacity - elementData.length > 0)
     // 擴(kuò)容操作
        grow(minCapacity);
}
private void grow(int minCapacity) {
    // 老的長(zhǎng)度, 初始化時(shí)為 0, 
    int oldCapacity = elementData.length;
    // 新的長(zhǎng)度此時(shí) 0 + (0 >> 1), newCapacity = 0
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 初始化場(chǎng)景: 0 - 10 < 0 ? true newCapacity = 10
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // 初始化場(chǎng)景: 10 - 2147483639 > 0 返回 false
    if (newCapacity - MAX_ARRAY_SIZE > 0)
     // 超大長(zhǎng)度才可以執(zhí)行這個(gè)方法, 必須大于 MAX_ARRAY_SIZE 一般不會(huì)
        newCapacity = hugeCapacity(minCapacity);
    // 復(fù)制原數(shù)組中的元素, 并擴(kuò)容
    elementData = Arrays.copyOf(elementData, newCapacity);
}

上看說(shuō)的是初始化場(chǎng)景,下面看一下其他場(chǎng)景,也是相當(dāng)簡(jiǎn)單

private void ensureCapacityInternal(int minCapacity) {
 /*
 calculateCapacity() 方法, 正常擴(kuò)容返回 size + 1, 比如 10 + 1, 因?yàn)槟J(rèn)長(zhǎng)度為 10 當(dāng)再次新增數(shù)據(jù)時(shí)就會(huì)出發(fā)擴(kuò)容
 ensureExplicitCapacity() 方法, 調(diào)用擴(kuò)容
 */
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) { 
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    /*
 elementData 不等于空數(shù)組
 返回當(dāng)前的 size + 1, 即 10 + 1 返回 11
 */
    return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
    // 增量, 記錄修改/更新次數(shù)
    modCount++;  
    
    // 其他: 11 - 10 > 0 true, 觸發(fā)擴(kuò)容, 如果當(dāng)前下表是 5 的話 5 + 1 =6, 6 < 10 是, 此時(shí)不會(huì)出發(fā)擴(kuò)容
    if (minCapacity - elementData.length > 0)
     // 擴(kuò)容操作
        grow(minCapacity);
}
private void grow(int minCapacity) {
    // 老的長(zhǎng)度 10
    int oldCapacity = elementData.length;
    // 新的長(zhǎng)度此時(shí) 10 + (10 >> 1), newCapacity = 15
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 15 - 11 < 0 ? false
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // 15 - 2147483639 > 0 返回 false
    if (newCapacity - MAX_ARRAY_SIZE > 0)
     // 超大長(zhǎng)度才可以執(zhí)行這個(gè)方法, 必須大于 MAX_ARRAY_SIZE 一般不會(huì)
        newCapacity = hugeCapacity(minCapacity);
    // 復(fù)制原數(shù)組中的元素, 并擴(kuò)容 newCapacity = 15
    elementData = Arrays.copyOf(elementData, newCapacity);
}

結(jié)論

1、 觸發(fā)擴(kuò)容的關(guān)鍵是

當(dāng)前 size + 1 是否大于當(dāng)前容量,如果大于容量則證明,集合不夠用了,需要擴(kuò)容。如果小與當(dāng)前容量則證明集合還有容量不需要擴(kuò)容!

2、 每次擴(kuò)容的大小是

oldCapacity + (oldCapacity >> 1) 即: 10 + (10 >> 1)

即:當(dāng)前容量的 1.5 倍!

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • MyBatis?typeHandler接口的定義和使用

    MyBatis?typeHandler接口的定義和使用

    TypeHandler被稱作類型處理器,MyBatis在設(shè)置預(yù)處理語(yǔ)句中的參數(shù)或從結(jié)果集中取出一個(gè)值時(shí),都會(huì)用類型處理器將Java對(duì)象轉(zhuǎn)化為數(shù)據(jù)庫(kù)支持的類型或者將獲取到數(shù)據(jù)庫(kù)值以合適的方式轉(zhuǎn)換成Java類型,感興趣的同學(xué)可以參考下文
    2023-05-05
  • 使用@JsonFormat的一個(gè)坑及解決

    使用@JsonFormat的一個(gè)坑及解決

    這篇文章主要介紹了使用@JsonFormat的一個(gè)坑及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java編程實(shí)現(xiàn)比對(duì)兩個(gè)文本文件并標(biāo)記相同與不同之處的方法

    Java編程實(shí)現(xiàn)比對(duì)兩個(gè)文本文件并標(biāo)記相同與不同之處的方法

    這篇文章主要介紹了Java編程實(shí)現(xiàn)比對(duì)兩個(gè)文本文件并標(biāo)記相同與不同之處的方法,涉及java針對(duì)文本文件的讀取、遍歷、判斷等相關(guān)操作技巧,需要的朋友可以參考下
    2017-10-10
  • Mybatis-Spring源碼分析圖解

    Mybatis-Spring源碼分析圖解

    這篇文章主要介紹了Mybatis-Spring源碼分析,本文通過實(shí)例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-11-11
  • 詳解idea maven nexus 常見命令配置

    詳解idea maven nexus 常見命令配置

    這篇文章主要介紹了idea maven nexus 常見命令配置的相關(guān)知識(shí),通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • 如何解決struts2日期類型轉(zhuǎn)換

    如何解決struts2日期類型轉(zhuǎn)換

    在Struts2中,一般的內(nèi)置類型都會(huì)在由系統(tǒng)自動(dòng)進(jìn)行轉(zhuǎn)換.但是Date類型好像有時(shí)候行,有時(shí)候不行。比如我這次,本地運(yùn)行正常,一上測(cè)試服務(wù)器就不行了。這個(gè)轉(zhuǎn)換類是從網(wǎng)上看的:
    2013-03-03
  • 深入理解Java中的字符串類型

    深入理解Java中的字符串類型

    這篇文章主要介紹了Java中的字符串類型,需要的朋友可以參考下
    2014-02-02
  • Mybatis集成Spring的實(shí)例代碼_動(dòng)力節(jié)點(diǎn)Java 學(xué)院整理

    Mybatis集成Spring的實(shí)例代碼_動(dòng)力節(jié)點(diǎn)Java 學(xué)院整理

    這篇文章主要介紹了Mybatis集成Spring的實(shí)例代碼,需要的朋友可以參考下
    2017-09-09
  • Java圖形用戶界面之列表框

    Java圖形用戶界面之列表框

    列表框通過Swing組件JList產(chǎn)生,其總是在屏幕上占據(jù)固定行數(shù)的空間。這篇文章主要介紹了java圖形用戶界面之列表框的相關(guān)資料,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-10-10
  • Java快速掌握Vector類方法

    Java快速掌握Vector類方法

    Vector?類實(shí)現(xiàn)了一個(gè)動(dòng)態(tài)數(shù)組。和?ArrayList?很相似,但是兩者是不同的:Vector?是同步訪問的;Vector?包含了許多傳統(tǒng)的方法,這些方法不屬于集合框架
    2022-03-03

最新評(píng)論

洛阳市| 布尔津县| 康定县| 广东省| 儋州市| 阳高县| 个旧市| 垣曲县| 白城市| 虹口区| 遂平县| 积石山| 开鲁县| 天镇县| 江门市| 浏阳市| 商城县| 孝昌县| 汝城县| 秦皇岛市| 镇赉县| 喜德县| 丰宁| 普兰店市| 瑞安市| 时尚| 漾濞| 定日县| 洪湖市| 长兴县| 福鼎市| 建德市| 道真| 天柱县| 民权县| 镇雄县| 巨野县| 涿鹿县| 桂平市| 佳木斯市| 保山市|