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

聊一聊jdk1.8中的ArrayList 底層數(shù)組是如何擴(kuò)容的

 更新時(shí)間:2020年08月17日 11:28:55   作者:光哥_帥  
這篇文章主要介紹了聊一聊jdk1.8中的ArrayList 底層數(shù)組是如何擴(kuò)容的,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

一、結(jié)論先行

ArrayList在JDK1.8與JDK1.7底層區(qū)別

JDK1.7:ArrayList像餓漢式,直接創(chuàng)建一個(gè)初始容量為10的數(shù)組,當(dāng)數(shù)組的長(zhǎng)度不能容下所添加的內(nèi)容時(shí)候,數(shù)組會(huì)擴(kuò)容至原大小的1.5倍

JDK1.8:ArrayList像懶漢式,一開(kāi)始創(chuàng)建一個(gè)長(zhǎng)度為0的數(shù)組,當(dāng)添加第一個(gè)元素時(shí)再創(chuàng)建一個(gè)始容量為10的數(shù)組,當(dāng)數(shù)組的長(zhǎng)度不能容下所添加的內(nèi)容時(shí)候,數(shù)組會(huì)擴(kuò)容至原大小的1.5倍

二、JDK1.8 ArrayList源碼分析

1、ArrayList 屬性

  /**
   * 默認(rèn)容量的大小
   */
  private static final int DEFAULT_CAPACITY = 10;

  /**
   * 空數(shù)組常量
   */
  private static final Object[] EMPTY_ELEMENTDATA = {};

  /**
   * 默認(rèn)的空數(shù)組常量,我們將其與EMPTY_ELEMENTDATA區(qū)分開(kāi)來(lái),
   * 以便知道添加第一個(gè)元素時(shí)需要膨脹多少
   */
  private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};


  /**
   * 存放元素的數(shù)組,從這可以發(fā)現(xiàn)ArrayList的底層實(shí)現(xiàn)就是一個(gè)Object數(shù)組
   */
  transient Object[] elementData; 

  /**
   * 數(shù)組中包含元素的個(gè)數(shù)
   */
  private int size;

  /**
   *數(shù)組的最大上限,超過(guò)上限可能導(dǎo)致OutOfMemoryError錯(cuò)誤
   */
  private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

2、構(gòu)造方法

  /**
   * 指定大小的時(shí)候,elementData就變成了我們所指定的初始化大小了
   */
  public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
      this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
      this.elementData = EMPTY_ELEMENTDATA;
    } else {
      throw new IllegalArgumentException("Illegal Capacity: "+
                        initialCapacity);
    }
  }

  /**
   *  根據(jù)上面的屬性可知,DEFAULTCAPACITY_EMPTY_ELEMENTDATA={},所以默認(rèn)創(chuàng)建的是  一個(gè)大小為0的空數(shù)組
   */
  public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
  }

從上面我可以知道,jkd1.8中默認(rèn)的是大小為0空數(shù)組,這個(gè)和jdk1.7之前都是不一樣的,這和設(shè)計(jì)模式的懶漢式很有相似之處

3、add 方法,底層擴(kuò)容機(jī)制

 /**
   * 在指定的位置插入指定的元素
   */
  public void add(int index, E element) {
    rangeCheckForAdd(index);

    ensureCapacityInternal(size + 1); // Increments modCount!!
    System.arraycopy(elementData, index, elementData, index + 1,
             size - index);
    elementData[index] = element;
    size++;
  }

  /**
   * 將指定的參數(shù)添加到列表的末尾,其中size是數(shù)組中包含元素的個(gè)數(shù)
   * @param e 以附加到此列表中
   */
  public boolean add(E e) {
    ensureCapacityInternal(size + 1); 
    // 數(shù)組的下標(biāo)從0開(kāi)始,所以size++保證elementData每次添加完一個(gè)元素,元素個(gè)數(shù)也隨之加1
    elementData[size++] = e;
    return true;
  }

 // 參數(shù)minCapacity 表達(dá)的意思是所需數(shù)組的最小容量,也就是size+1, 上面?zhèn)鞯闹?
  private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
  }


  /**
  * 計(jì)算容量的方法,
  */
  private static int calculateCapacity(Object[] elementData, int minCapacity) {
   // 如果是一個(gè)空數(shù)組,
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
    // DEFAULT_CAPACITY從屬性可知默認(rèn)是10,minCapactity為數(shù)組的大小
    // 由此可以看出他是在添加第一個(gè)元素的時(shí)候,才創(chuàng)建了長(zhǎng)度為10的數(shù)組
      return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
  }


 private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
  // 如果此時(shí)所需要的最小的長(zhǎng)度大于原數(shù)組的長(zhǎng)度,則需要進(jìn)行擴(kuò)容
    if (minCapacity - elementData.length > 0)
      grow(minCapacity);
  }
  
  /**
   * 增加容量,以確保它至少可以容納minCapacity指定的元素?cái)?shù)量。
   * @param minCapacity 表示所需要的擴(kuò)容的量
   */
  private void grow(int minCapacity) {
    int oldCapacity = elementData.length; // 原數(shù)組的長(zhǎng)度
   //原數(shù)組的長(zhǎng)度+原數(shù)組的長(zhǎng)度/2,表示擴(kuò)容了原來(lái)大小的1.5倍,newCapacity :表示需要擴(kuò)容的量
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
      newCapacity = minCapacity;
   // 如果需要的擴(kuò)容量大于了本類(lèi)中定義的最大擴(kuò)容限制,則擴(kuò)容到 int 類(lèi)型最大長(zhǎng)度
    if (newCapacity - MAX_ARRAY_SIZE > 0)
      newCapacity = hugeCapacity(minCapacity);
   // 調(diào)用的是數(shù)組的復(fù)制方法,實(shí)現(xiàn)擴(kuò)容
    elementData = Arrays.copyOf(elementData, newCapacity);
  }

  private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
      throw new OutOfMemoryError();
   // 如若需要擴(kuò)容的量大于最大限制,則擴(kuò)容量改為 int 最大限制量:2147483647,否則為本類(lèi)中所限制長(zhǎng)度:2147483647-8
    return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;
  }

解釋?zhuān)篿nt newCapacity = oldCapacity + (oldCapacity >> 1);

這個(gè)>>1 表示的是右移一位,轉(zhuǎn)為二進(jìn)制我們應(yīng)該一下就明白了:比如16,轉(zhuǎn)為2進(jìn)制為

10000,右移一位則成為01000,換為十進(jìn)制就是8,擴(kuò)容的大小也就相當(dāng)于oldCapacity +oldCapacity /2了

4、總結(jié)

jdk1.8中:

add方法總結(jié)起來(lái)就是在插入數(shù)據(jù)之前,會(huì)先檢查是否需要擴(kuò)容,通過(guò)無(wú)參構(gòu)造方法來(lái)創(chuàng)建 ArrayList 時(shí),它的大小其實(shí)是為 0 的,只有在使用到 的時(shí)候,才會(huì)通過(guò) grow 方法去創(chuàng)建一個(gè)大小為 10 的數(shù)組。

public boolean add(E e) 方法的復(fù)雜度為O(1),涉及到擴(kuò)容的操作是非常少的,可以忽略不計(jì),它的本質(zhì)是添加元素到數(shù)組中最后一個(gè)元素的后面。

public void add(int index, E element) 這個(gè)是帶指定下標(biāo)的add 方法,復(fù)雜度為O(n),因?yàn)樯婕暗綌?shù)組中元素的移動(dòng),這一操作非常耗時(shí),由此可見(jiàn)ArrayList不適合插入和刪除操作。

三、ArrayList與Vector的區(qū)別

現(xiàn)在Vector已經(jīng)很少有人用了,這里只是簡(jiǎn)單的記錄下二者區(qū)別:

1、ArrayList線程不安全,Vector是線程安全的

通過(guò)Vector源碼我們可以知道很多方法都是加了synchronized關(guān)鍵字,所以Vector是線程安全的。

2、ArrayList創(chuàng)建的默認(rèn)大小為0,Vector創(chuàng)建時(shí)的默認(rèn)大小是10。

3、ArrayList 每次擴(kuò)容都以當(dāng)前數(shù)組大小的 1.5 倍去擴(kuò)容, Vector 每次擴(kuò)容都以當(dāng)前數(shù)組大小的 2 倍去擴(kuò)容。當(dāng)指定了 capacityIncrement 之 后,每次擴(kuò)容僅在原先基礎(chǔ)上增加 capacityIncrement 個(gè)單位空間。

補(bǔ)充知識(shí):ArrayList詳解,底層是數(shù)組,實(shí)現(xiàn)Serializable接口

一、對(duì)于ArrayList需要掌握的七點(diǎn)內(nèi)容

ArrayList的創(chuàng)建:即構(gòu)造器

往ArrayList中添加對(duì)象:即add(E)方法

獲取ArrayList中的單個(gè)對(duì)象:即get(int index)方法

刪除ArrayList中的對(duì)象:即remove(E)方法

遍歷ArrayList中的對(duì)象:即iterator,在實(shí)際中更常用的是增強(qiáng)型的for循環(huán)去做遍歷

判斷對(duì)象是否存在于ArrayList中:contain(E)

ArrayList中對(duì)象的排序:主要取決于所采取的排序算法(以后講)

二、源碼分析

2.1、ArrayList的創(chuàng)建(常見(jiàn)的兩種方式)

List<String> strList = new ArrayList<String>();

List<String> strList2 = new ArrayList<String>(2);

ArrayList源代碼:

基本屬性:

//對(duì)象數(shù)組:ArrayList的底層數(shù)據(jù)結(jié)構(gòu)
private transient Object[] elementData;
//elementData中已存放的元素的個(gè)數(shù),注意:不是elementData的容量
private int size;

注意:

transient關(guān)鍵字的作用:在采用Java默認(rèn)的序列化機(jī)制的時(shí)候,被該關(guān)鍵字修飾的屬性不會(huì)被序列化。

ArrayList類(lèi)實(shí)現(xiàn)了java.io.Serializable接口,即采用了Java默認(rèn)的序列化機(jī)制

上面的elementData屬性采用了transient來(lái)修飾,表明其不使用Java默認(rèn)的序列化機(jī)制來(lái)實(shí)例化,但是該屬性是ArrayList的底層數(shù)據(jù)結(jié)構(gòu),在網(wǎng)絡(luò)傳輸中一定需要將其序列化,之后使用的時(shí)候還需要反序列化,那不采用Java默認(rèn)的序列化機(jī)制,那采用什么呢?直接翻到源碼的最下邊有兩個(gè)方法,發(fā)現(xiàn)ArrayList自己實(shí)現(xiàn)了序列化和反序列化的方法

View Code

構(gòu)造器:

/**
* 創(chuàng)建一個(gè)容量為initialCapacity的空的(size==0)對(duì)象數(shù)組
*/
public ArrayList(int initialCapacity) {
super();//即父類(lèi)protected AbstractList() {}
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity:" + initialCapacity);
this.elementData = new Object[initialCapacity];
}

/**
* 默認(rèn)初始化一個(gè)容量為10的對(duì)象數(shù)組
*/
public ArrayList() {
this(10);//即上邊的public ArrayList(int initialCapacity){}構(gòu)造器
}

在我們執(zhí)行new ArrayList<String>()時(shí),會(huì)調(diào)用上邊的無(wú)參構(gòu)造器,創(chuàng)造一個(gè)容量為10的對(duì)象數(shù)組。

在我們執(zhí)行new ArrayList<String>(2)時(shí),會(huì)調(diào)用上邊的public ArrayList(int initialCapacity),創(chuàng)造一個(gè)容量為2的對(duì)象數(shù)組。

注意:

上邊有參構(gòu)造器的super()方法是ArrayList父類(lèi)AbstractList的構(gòu)造方法,這個(gè)構(gòu)造方法如下,是一個(gè)空構(gòu)造方法:

protected AbstractList() {
}

在實(shí)際使用中,如果我們能對(duì)所需的ArrayList的大小進(jìn)行判斷,有兩個(gè)好處:

節(jié)省內(nèi)存空間(eg.我們只需要放置兩個(gè)元素到數(shù)組,new ArrayList<String>(2))

避免數(shù)組擴(kuò)容(下邊會(huì)講)引起的效率下降(eg.我們只需要放置大約37個(gè)元素到數(shù)組,new ArrayList<String>(40))

2.2、往ArrayList中添加對(duì)象(常見(jiàn)的兩個(gè)方法add(E)和addAll(Collection<? extends E> c))

以上這篇聊一聊jdk1.8中的ArrayList 底層數(shù)組是如何擴(kuò)容的就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java使用定時(shí)器實(shí)現(xiàn)監(jiān)聽(tīng)數(shù)據(jù)變化

    java使用定時(shí)器實(shí)現(xiàn)監(jiān)聽(tīng)數(shù)據(jù)變化

    這篇文章主要為大家詳細(xì)介紹了Java如何使用定時(shí)器監(jiān)聽(tīng)數(shù)據(jù)變化,當(dāng)滿足某個(gè)條件時(shí)(例如沒(méi)有數(shù)據(jù)更新)自動(dòng)執(zhí)行某項(xiàng)任務(wù),有興趣的可以了解下
    2023-11-11
  • 淺談Java設(shè)計(jì)模式之七大設(shè)計(jì)原則

    淺談Java設(shè)計(jì)模式之七大設(shè)計(jì)原則

    在此之前,我已經(jīng)寫(xiě)過(guò)很多篇關(guān)于設(shè)計(jì)模式的文章.但都比較草草的理解和簡(jiǎn)單的實(shí)現(xiàn),并未深入理解.為了更加深入感受Java設(shè)計(jì)的魅力,編程的藝術(shù),今天進(jìn)行了七大設(shè)計(jì)原則的學(xué)習(xí)理解,后續(xù)進(jìn)行23種設(shè)計(jì)模式的深入學(xué)習(xí)探究,需要的朋友可以參考下
    2021-05-05
  • Jmeter對(duì)接口測(cè)試入?yún)?shí)現(xiàn)MD5加密

    Jmeter對(duì)接口測(cè)試入?yún)?shí)現(xiàn)MD5加密

    這篇文章主要介紹了Jmeter對(duì)接口測(cè)試入?yún)?shí)現(xiàn)MD5加密,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • 第一次編寫(xiě)Java流布局圖形界面

    第一次編寫(xiě)Java流布局圖形界面

    這篇文章主要為大家詳細(xì)介紹了第一次編寫(xiě)Java流布局圖形界面的相關(guān)代碼,感興趣的小伙伴們可以參考一下
    2016-08-08
  • 淺談Java中的LinkedHashSet哈希鏈表

    淺談Java中的LinkedHashSet哈希鏈表

    這篇文章主要介紹了淺談Java中的LinkedHashSet哈希鏈表,LinkedHashSet 是 Java 中的一個(gè)集合類(lèi),它是 HashSet 的子類(lèi),并實(shí)現(xiàn)了 Set 接口,與 HashSet 不同的是,LinkedHashSet 保留了元素插入的順序,并且具有 HashSet 的快速查找特性,需要的朋友可以參考下
    2023-09-09
  • 淺析Jmeter多用戶(hù)token使用問(wèn)題

    淺析Jmeter多用戶(hù)token使用問(wèn)題

    這篇文章主要介紹了Jmeter多用戶(hù)token使用問(wèn)題,通過(guò)具體的例子給大家介紹了Jmeter多用戶(hù)token使用場(chǎng)景接口分析,需要的朋友可以參考下
    2021-10-10
  • Java的Synchronized關(guān)鍵字學(xué)習(xí)指南(全面 & 詳細(xì))

    Java的Synchronized關(guān)鍵字學(xué)習(xí)指南(全面 & 詳細(xì))

    這篇文章主要給大家介紹了關(guān)于Java的Synchronized關(guān)鍵字的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • 如何解決java.lang.ClassNotFoundException: com.mysql.jdbc.Driver問(wèn)題

    如何解決java.lang.ClassNotFoundException: com.mysql.jdbc.Dr

    這篇文章主要介紹了如何解決java.lang.ClassNotFoundException: com.mysql.jdbc.Driver問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • mybatis 自定義實(shí)現(xiàn)攔截器插件Interceptor示例

    mybatis 自定義實(shí)現(xiàn)攔截器插件Interceptor示例

    這篇文章主要介紹了mybatis 自定義實(shí)現(xiàn)攔截器插件Interceptor,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • Spring與Redis集成的正確方式流程詳解

    Spring與Redis集成的正確方式流程詳解

    這篇文章主要為大家介紹了Spring與Redis集成的正確方式流程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06

最新評(píng)論