集合運用之在明確場景下,爲集合指定初始容量

集合基本上面試時面試必問的,我一個同事曾經面試時就被問過集合的默認長度是多少。下面我們就ArrayList集合的長度來說說指定初始容量的事。

List<Persion> list = new ArrayList<Persion>();

相信大部分在使用集合是,都是類似的聲明一個集合,然後用add、remove等方法對集合進行操作,而且因爲它是自動管理長度的,所以不用我們特別費心超長的問題,這確實是一個非常好的優點,但也有我們必須要注意的事項。下面我以ArrayList爲例深入瞭解下java是如何實現自動長度的動態管理,從add方法開始,代碼如下(我的是jdk1.7):

public boolean add(E paramE)
   {
   //擴展長度
    ensureCapacityInternal(this.size + 1);
    //追加元素
     this.elementData[(this.size++)] = paramE;
     return true;
   }

我們知道ArrayList是一個大小可變的,但它在底層使用的是數組存儲(也就是elementData變量),而且數組是定長的,要實行動態長度必然要進行長度的擴展,代碼如下:

private void ensureCapacityInternal(int paramInt) {
     this.modCount += 1;

     if (paramInt - this.elementData.length > 0)
      grow(paramInt);
   }

   private void grow(int paramInt)
   {
   //上次(原始)定義的數組長度
     int i = this.elementData.length;
     int j = i + (i >> 1);
     if (j - paramInt < 0)
      j = paramInt;
     if (j - 2147483639 > 0) {
       j = hugeCapacity(paramInt);
     }
     this.elementData = Arrays.copyOf(this.elementData, j);
   }

   private static int hugeCapacity(int paramInt) {
     if (paramInt < 0)
       throw new OutOfMemoryError();
     return paramInt > 2147483639 ? 2147483647 : 2147483639;
  }

我們看到新數組的長度計算方法,並不是增加一個元素,elementData 的長度就加1,而是在達到elementData 長度的臨界點時,纔將elementData 擴容1.5倍(i + (i >> 1))右移1位相當於除以2,這樣有什麼好處呢?避免了多次調用copyOf方法的性能開銷,否則沒加一個元素都要擴容一次,那性能將會非常糟糕。
知道了擴容原則,還有一個問題:elementData 的默認長度是多少呢?答案是10,比如new ArrayList(),則elementData 的初始長度是10.代碼如下:

//無參構造,通常用的最多的就是這個
public ArrayList()
  {
  //指定數組長度的有參構造
    this(10);
  }
//指定數組長度的有參構造
public ArrayList(int paramInt)
   {
    if (paramInt < 0) {
       throw new IllegalArgumentException("Illegal Capacity: " + paramInt);
     }
     this.elementData = new Object[paramInt];
  }

默認初始化時聲明瞭一個長度爲10的數組,在通過add方法增加弟11個元素時,ArrayList類就自動擴展了,新的elementData 數組長度是10+(10>>1),也就是15,可以看出,如果不設置初始容量,系統就按照1.5倍的規則擴容,每次擴容都是一次數組的拷貝,如果數據量很大,這樣的拷貝會非常耗費資源,而且效率非常低下。如果我們已經知道一個ArrayList的可能長度,然後對ArrayList設置一個初始容量則可以顯著提高系統性能。

發佈了46 篇原創文章 · 獲贊 48 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章