一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - Java中的ArrayList容量及擴(kuò)容方式

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

2021-12-30 13:23zx2015216856 Java教程

這篇文章主要介紹了Java中的ArrayList容量及擴(kuò)容方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

查看JDK1.8 ArrayList的源代碼

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

?
1
2
3
4
/**
  * Default initial capacity.
  */
 private static final int DEFAULT_CAPACITY = 10;

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

?
1
2
3
4
5
6
7
/**
 * 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ù)組對象有一個額外的元數(shù)據(jù),用于表示數(shù)組的大小;

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

8bytes用來存儲size;

3、擴(kuò)容方式:

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

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

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
  * 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)造方法,這個比較重要

先看下屬性

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
帶參構(gòu)造器, 參數(shù)為容量大小, 例如: 初始化一個容器為 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)造器

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

不帶參構(gòu)造器

?
1
2
3
4
5
6
7
/*
不帶參構(gòu)造器就像我們平時使用一樣, 直接 new 一個 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() 方法可以直接得到答案。

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
private void ensureCapacityInternal(int minCapacity) {
 /*
 calculateCapacity() 方法, 剛初始化時會返回 10, 其他情況返回當(dāng)前 size + 1
 ensureExplicitCapacity() 方法, 調(diào)用擴(kuò)容
 */
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
 /*
 使用無參構(gòu)造器創(chuàng)建創(chuàng)建 ArrayList 的集合, 此時一定是相等的
 */
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
     /*
     兩數(shù)相比返回最大值, 此時 Math.max(10, 1);
     默認(rèn)容量, 由此而來
     */
        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) {
    // 老的長度, 初始化時為 0,
    int oldCapacity = elementData.length;
    // 新的長度此時 0 + (0 >> 1), newCapacity = 0
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 初始化場景: 0 - 10 < 0 ? true newCapacity = 10
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // 初始化場景: 10 - 2147483639 > 0 返回 false
    if (newCapacity - MAX_ARRAY_SIZE > 0)
     // 超大長度才可以執(zhí)行這個方法, 必須大于 MAX_ARRAY_SIZE 一般不會
        newCapacity = hugeCapacity(minCapacity);
    // 復(fù)制原數(shù)組中的元素, 并擴(kuò)容
    elementData = Arrays.copyOf(elementData, newCapacity);
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
private void ensureCapacityInternal(int minCapacity) {
 /*
 calculateCapacity() 方法, 正常擴(kuò)容返回 size + 1, 比如 10 + 1, 因?yàn)槟J(rèn)長度為 10 當(dāng)再次新增數(shù)據(jù)時就會出發(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 是, 此時不會出發(fā)擴(kuò)容
    if (minCapacity - elementData.length > 0)
     // 擴(kuò)容操作
        grow(minCapacity);
}
private void grow(int minCapacity) {
    // 老的長度 10
    int oldCapacity = elementData.length;
    // 新的長度此時 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í)行這個方法, 必須大于 MAX_ARRAY_SIZE 一般不會
        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ò)容的大小是

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

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

以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持服務(wù)器之家。

原文鏈接:https://blog.csdn.net/zx2015216856/article/details/82597104

延伸 · 閱讀

精彩推薦
  • Java教程20個非常實(shí)用的Java程序代碼片段

    20個非常實(shí)用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實(shí)用的Java程序片段,對java開發(fā)項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java BufferWriter寫文件寫不進(jìn)去或缺失數(shù)據(jù)的解決

    Java BufferWriter寫文件寫不進(jìn)去或缺失數(shù)據(jù)的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進(jìn)去或缺失數(shù)據(jù)的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經(jīng)有好久沒有升過級了。升級完畢重啟之后,突然發(fā)現(xiàn)好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java實(shí)現(xiàn)搶紅包功能

    Java實(shí)現(xiàn)搶紅包功能

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發(fā)現(xiàn)了對于集合操作轉(zhuǎn)換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點(diǎn),所以這篇文章主要給大家介紹了關(guān)于Java8中S...

    阿杜7482021-02-04
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關(guān)于小米推送Java代碼,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩(wěn)中求8032021-07-12
  • Java教程xml與Java對象的轉(zhuǎn)換詳解

    xml與Java對象的轉(zhuǎn)換詳解

    這篇文章主要介紹了xml與Java對象的轉(zhuǎn)換詳解的相關(guān)資料,需要的朋友可以參考下...

    Java教程網(wǎng)2942020-09-17
主站蜘蛛池模板: 99热视| 激情三级做爰在线观看激情 | 亚洲国产成人久久午夜 | 精品精品国产自在香蕉网 | 亚洲社区在线 | 大逼美女| 99热这里只有精品国产在热久久 | 免费视频专区一国产盗摄 | 日本韩国推理片免费观看网站 | 99爱视频| 亚洲福利一区二区精品秒拍 | 四虎国产精品免费入口 | 四虎最新永久在线精品免费 | 99r在线观看 | 亚洲成人免费观看 | 色多多多 | 成人免费国产欧美日韩你懂的 | 日本人做受全过程视频 | 爽好舒服宝贝添奶吻戏 | 国产精品一二三 | 韩国漂亮美女三级在线观看 | 乳女教师欲乱动漫无修版动画3d | 国产欧美视频在线观看 | 日本漫画工囗全彩内番e绅 日本伦理动漫在线观看 | 韩国免费特一级毛片 | 久久青青草原精品国产软件 | 国产精品久久久久无毒 | 好爽好紧小雪别夹小说 | 美女脱了内裤让男生尿囗 | 国产亚洲精品精品国产亚洲综合 | 小sao货水好多真紧h的视频 | 日韩视频在线观看中字 | 魔兽官方小说 | 福利一区在线观看 | 人人爱天天做夜夜爽88 | 教师波多野结衣在线播放 | 欧美日韩国产亚洲一区二区 | 国产精品露脸国语对白99 | 操操综合网| 日韩一区二区在线视频 | 邪恶肉肉全彩色无遮琉璃神社 |