1. 程式人生 > >ArrayList自動擴容解析

ArrayList自動擴容解析

  1. 探索ArrayList自動改變size真相  
  2. ArrayList的列表物件實質上是儲存在一個引用型數組裡的,有人認為該陣列有“自動增長機制”可以自動改變size大小。正式地說,該陣列是無法改變  
  3. 大小的,實際上它只是改變了該引用型陣列的指向而已。下面,讓我們來看看java是怎樣實現ArrayList類的。  
  4. 一、ArrayList類的實質  
  5.      ArrayList底層採用Object型別的陣列實現,當使用不帶引數的構造方法生成ArrayList物件時,  
  6. 實際上會在底層生成一個長度為10的Object型別陣列。  
  7.     首先,ArrayList定義了一個私有的未被序列化的陣列elementData,用來儲存ArrayList的物件列表(注意只定義未初始):  
  8.   privatetransient Object[] elementData;  
  9.     其次,以指定初始容量(Capacity)或把指定的Collection轉換為引用型陣列後例項化elementData陣列;如果沒有指定,則預置初始容量為10進行  
  10. 例項化。把私有陣列預先例項化,然後通過copyOf方法覆蓋原陣列,是實現自動改變ArrayList的大小(size)的關鍵。有人說ArrayList是複雜的陣列,我  
  11. 認為不如說ArrayList是關於陣列的系統的方法組合。  
  12.   ArrayList的構造方法原始碼如下:  
  13.     // 用指定的初始容量構造一個空列表。
  14.     public
     ArrayList(int initialCapacity) {  
  15.         super();  
  16.         if (initialCapacity < 0)  
  17.             thrownew IllegalArgumentException("Illegal Capacity: "+initialCapacity);  
  18.         this.elementData = new Object[initialCapacity];//屬性指向新建長度為初始容量的臨時陣列
  19.     }  
  20.     // 使用初始容量10構造一個空列表
  21.     public ArrayList() {  
  22.         this(10);  
  23.     }  
  24.     / *構造包含利用collection的迭代器按順序返回的指定collection元素的列表  
  25.      * @param c 集合,它的元素被用來放入列表t  
  26.      * @throws NullPointerException 如果指定集合為 null
  27.      */  
  28.     public ArrayList(Collection<? extends E> c) {  
  29.         elementData = c.toArray();//用Collection初始化陣列elementData
  30.         size = elementData.length;  
  31.         if (elementData.getClass() != Object[].class)  
  32.             elementData = Arrays.copyOf(elementData, size, Object[].class);  
  33.     }  
  34. 二、ArrayList實現自動改變size機制  
  35.    為了實現這一機制,java引進了Capacity和size概念,以區別陣列的length。為了保證使用者增加新的列表物件,java設定了最小容量(minCapacity)  
  36. ,通常情況上,它大於列表物件的數目,所以Capactiy雖然就是底層陣列的長度(length),但是對於終端使用者來講,它是無意義的。而size儲存著列表  
  37. 物件的數量,才是終端使用者所需要的。為了防止使用者錯誤修改,這一屬性被設定為privae的,不過可以通過size()獲取。  
  38.    下面,對ArrayList的初始以及其列表物件的增加和刪除等三種情況下的size自動改變機制進行分析。  
  39.    1、初始Capacity和size值。  
  40.    從上面給出的ArrayList構造方法原始碼中,我們不難看出Capacity初始值(initialCapacity)可以由使用者直接指定或由使用者指定的Collection集合存  
  41. 儲的物件數目確定,如果沒有指定,系統預設為10。而size的被宣告為int型變數,預設為0,當用戶指定Collection建立ArrayList時,size值等於  
  42. initialCapacity。  
  43.    2、add()方法  
  44.     該方法的原始碼如下:  
  45.     publicboolean add(E e) {  
  46.         ensureCapacityInternal(size + 1);  
  47.         elementData[size++] = e;//新增物件時,自增size
  48.         returntrue;  
  49.     }  
  50.     方法中呼叫的ensureCapacityInternal主要用來調整容量,修改elementData陣列的指向。其中涉及到3個方法的呼叫,其核心在於grow方法:  
  51.     privatevoid ensureCapacityInternal(int minCapacity) {  
  52.         modCount++;//定義於ArrayList的父類AbstractList,用於儲存結構修改次數
  53.         // overflow-conscious code
  54.         if (minCapacity - elementData.length > 0)  
  55.             grow(minCapacity);  
  56.     }    
  57.     privatevoid grow(int minCapacity) {  
  58.         // overflow-conscious code
  59.         int oldCapacity = elementData.length;  
  60.         int newCapacity = oldCapacity + (oldCapacity >> 1);//新容量擴大到原容量的1.5倍,右移一位相關於原數值除以2。
  61.         if (newCapacity - minCapacity < 0)  
  62.             newCapacity = minCapacity;  
  63.         if (newCapacity - MAX_ARRAY_SIZE > 0)  
  64.             newCapacity = hugeCapacity(minCapacity);  
  65.         // minCapacity is usually close to size, so this is a win:
  66.         elementData = Arrays.copyOf(elementData, newCapacity);  
  67.     }  
  68.     privatestaticint hugeCapacity(int minCapacity) {  
  69.         if (minCapacity < 0// overflow
  70.             thrownew OutOfMemoryError();  
  71.         return (minCapacity > MAX_ARRAY_SIZE) ?  
  72.             Integer.MAX_VALUE :  
  73.             MAX_ARRAY_SIZE;//MAX_ARRAY_SIZE和Integer.MAX_VALUE為常量,詳細請參閱下面的註解
  74.     }  
  75.    通過以上程式碼,我們可知java自動增加ArrayList大小的思路是:向ArrayList新增物件時,原物件數目加1如果大於原底層陣列長度,則以適當長度新  
  76. 建一個原陣列的拷貝,並修改原陣列,指向這個新建陣列。原陣列自動拋棄(java垃圾回收機制會自動回收)。size則在向陣列新增物件,自增1。  
  77.    註解:  
  78.     //定義於該類的常量,用來分配陣列的size最大值。一些 VMs在數組裡保留字頭,試圖分配更大陣列時可能導致OutOfMemoryError:被請求陣列的
  79. size超出VM界限。  
  80.     privatestaticfinalint MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;  
  81.    //在java.lang.Integer類中常量MIN_VALUE、MAX_VALUE如下:
  82.    publicstaticfinalint   MIN_VALUE = 0x80000000;//整型取值區間下界:-2147483648
  83.    publicstaticfinalint   MAX_VALUE = 0x7fffffff;//整型取值區間上界:2147483647
  84.   //在java.util.AbstractList中modCount定義如下:
  85.   protectedtransientint modCount = 0;  
  86.     3、remove()方法  
  87.     該重構方法其一原始碼如下(其它的就不累述了):  
  88.     public E remove(int index) {  
  89.         rangeCheck(index);  
  90.         modCount++;  
  91.         E oldValue = elementData(index);  
  92.         int numMoved = size - index - 1;  
  93.         if (numMoved > 0)  
  94.             System.arraycopy(elementData, index+1, elementData, index,  
  95.                              numMoved);//將後面的列表物件前移
  96.         elementData[--size] = null// 陣列前移一位,size自減,空出來的位置置null,具體的物件的銷燬由Junk收集器負責
  97.         return oldValue;  
  98.     }  
  99.     privatevoid rangeCheck(int index) {//邊界檢查
  100.         if (index < 0 || index >= this.size)  
  101.            thrownew IndexOutOfBoundsException(outOfBoundsMsg(index));  
  102.     }  
  103.     E elementData(int index) {//獲取指定index所在位置的物件
  104.         return (E) elementData[index];  
  105.     }  
  106.     通過remove()原始碼的學習,我們不難看出,其改變ArrayList大小的核心與add()方法相似,都是同陣列拷貝。  
  107.     另外,如果確有必要,使用者也可以指定ArrayList例項的容量,可以有效的降低時間成本。它是通過呼叫ensureCapacityInternal來實現的,原始碼  
  108. 如下:  
  109.     publicvoid ensureCapacity(int minCapacity) {  
  110.         if (minCapacity > 0)  
  111.             ensureCapacityInternal(minCapacity);  
  112.     }  
  113.     因為size為private的,java給出方法來訪問它:  
  114.     publicint size() {  
  115.          checkForComodification();  
  116.          returnthis.size;  
  117.     }  

相關推薦

ArrayList自動擴容解析

探索ArrayList自動改變size真相   ArrayList的列表物件實質上是儲存在一個引用型數組裡的,有人認為該陣列有“自動增長機制”可以自動改變size大小。正式地說,該陣列是無法改變  

jdk 1.8 Arraylist自動擴容

以無參構造為例 第一步:呼叫add方法新增元素 public boolean add(E e) { ensureCapacityInternal(size + 1); // 新增元素前先呼叫ensureCapacityInternal方法 elementData[size

ArrayList自動擴容原理(底層實現)

探索ArrayList      ArrayList的列表物件實質上是儲存在一個引用型數組裡的,有人認為該陣列有“自動增長機制”可以自動改變size大小。正式地說,該陣列是無法改變 大小的,實際上它只是改變了該引用型陣列的指向而已。下面,讓我們來看看java是怎樣實現ArrayList類的。

【數組】- ArrayList自動擴容機制

exceptio ++ 表示 io操作 leg 當前 arraylist all length   不同的JDK版本的擴容機制可能有差異 實驗環境:JDK1.8    擴容機制:    當向ArrayList中添加元素的時候,ArrayList如果要滿足新元素的存儲超過Ar

C#深入研究ArrayList動態陣列自動擴容原理

1 void Test1() 2 { 3 ArrayList arrayList = new ArrayList(); 4 int length = 3; 5 for (int i = 0;

Java ArrayList自動擴容機制

注意: 不同的JDK版本的擴容機制可能有差異 實驗環境:JDK1.8 擴容機制: 當向ArrayList中新增元素的時候,ArrayList如果要滿足新元素的儲存超過ArrayList儲存新元素前的儲存能力,ArrayList會增強自身

ArrayList源碼解析(一)

unary 定義 cte 轉換 ora gif 成員類 con ins 目錄 1.位置 2.變量和常量 3.構造函數 4.trimToSize()方法 正文 源碼解析系列主要對Java的源碼進行詳細的說明,由於水平有限,難免出現錯誤或描述不準確的地方,還請大家指

Java集合幹貨系列-(一)ArrayList源碼解析

div imp ins bject 增加 toa tof capacity == 前言 今天來介紹下ArrayList,在集合框架整體框架一章中,我們介紹了List接口,ArrayList繼承了AbstractList,實現了List。ArrayList在工作中經常用到,所

Java 1.8 ArrayList源碼解析

cti 失敗 tex temp 發生 span 復制 move ise 1 // 非線程安全 2 // 繼承了AbstractList類 3 // 實現了List、RandomAccess、Cloneable、java.io.Serializable接口 4 // 後面3

集合為什麽可以自動擴容

image 擴容 觸發 mage inf 技術分享 lda 分享 clas 集合擴容的時機是Add(); 集合底層是通過兩個數組相互copy實現的。 擴容的本質就是將新數組長度擴容成舊數組長度的2倍,其實上就是調度Array.Copy(oldArray,0,d

ArrayList源碼解析

3.4 比較 empty 集合 了解 all iou obj row 1. 引言 上個月去一家公司面試 java 實習生,面試官說的一句話我記得很清楚 作為一個java 工程師,你不去看源碼是很難提高的。通過看源碼,不僅可以更快的解決問題,而且可以直接接觸到大牛寫的代碼,了

給jdk寫註釋系列之jdk1.6容器(1):ArrayList源碼解析

clone correct size 訪問 隨著 interface 指定 程序 最後一個元素 前言: 工作中經常聽到別人講“容器”,各種各樣的容器,話說到底什麽是容器,通俗的講“容器就是用來裝東西的器皿,比如:水桶就是用來盛水的,水桶就是一個容器。” ok,在我們寫程序的

ArrayList部分原始碼解析(JDK8)

List介面繼承自Collction(單列集合)介面,而ArrayList是List介面的一個重要實現類,當學習了ArrayList後再看其他實現類,如Vector和LinkedList(前者可以看作ArrayList的執行緒安全版,後者是ArrayList的連結串列版) 本文選取Array

自動擴容之Horizontal Pod Autoscaling(HPA)

我們通過手動執行kubectl scale命令,可以實現Pod擴容。但是,分散式系統要能夠根據當前負載的變化情況自動觸發水平擴充套件或縮容的行為,因為這一過程可能是頻繁發生的、不可預料的,所以手動控制的方式是不現實的。 - 因此,在Kubernetes1.1版本中首次釋出了這一重量級新特性

ArrayList,LinkedList原始碼解析

在java中,集合這一資料結構應用廣泛,應用最多的莫過於List介面下面的ArrayList和LinkedList; 我們先說List, 1 public interface List<E> extends Collection<E> { 2 //返回l

ArrayList擴容機制,以及和LinkedList,Vestor的區別

首先我們先了解一下它們三者 ArrayList:的底層實現為陣列儲存在記憶體中,執行緒不同步。可通過陣列下標的形式進行查詢,所以在查詢方面的效率較為出色,常用在查詢較多的情景下。 LinkedList:的底層實現為連結串列形式,也為執行緒不同步。而連結串列的底層也決定了它在查詢方面不如陣列底

語言小知識-Java ArrayList類 深度解析

花了一天時間,翻譯了一遍 java.util.ArrayList 類的原始碼(1700 多行,還是很有收穫的),包括註釋和程式碼解讀,並提了一些問題,也寫了下自己的理解 點我檢視 ArrayList 原始碼翻譯。 問題 1:ArrayList 的 size 和 capacity 怎麼理解? 如果

Java ArrayList類深度解析

花了一天時間,翻譯了一遍 java.util.ArrayList 類的原始碼(1700 多行,還是很有收穫的),包括註釋和程式碼解讀,並提了一些問題,也寫了下自己的理解 點我檢視 ArrayList 原始碼翻譯。 問題 1:ArrayList 的 size 和 capacity 怎麼理解?

Java基礎面試題(18)----ArrayList集合原始碼解析

我們對ArrayList集合的原始碼進行解析,只是寫出了增刪改查的方法。 首先我們來看一下ArrayList的資料結構 底層實際上是一個數組,在增加元素的時候,對陣列進行擴容,新增一個元素,容量增加1。 實際儲存的是順序儲存的結構,每個位置的元素都有執行的索

ArrayList擴容方式和擴容時機

初始化 ArrayList的底層是一個動態陣列,ArrayList首先會對傳進來的初始化引數initalCapacity進行判斷 如果引數等於0,則將陣列初始化為一個空陣列, 如果不等於0,將陣列