ArrayList源碼閱讀

導(dǎo)讀

ArrayList可以看成是動態(tài)數(shù)組,初始化時(shí),如果沒有分配空間劳澄,則默認(rèn)為10。每次進(jìn)行添加新元素時(shí)蜈七,會對該數(shù)組的剩余空間進(jìn)行判斷秒拔,如果不夠了則會在原基礎(chǔ)上增加3/2+1個(gè)空間。刪除元素時(shí)飒硅,是先獲取要刪除元素的位置砂缩,然后把該位置后面的元素向前移動一位,并把數(shù)組的最后一位賦值為null三娩。刪除和新增元素用的都是native方法System.arrayCopy()庵芭。

看一下平時(shí)主要使用的一些方法。

public ArrayList(int paramInt)
  {
    if (paramInt < 0)
      throw new IllegalArgumentException("Illegal Capacity: " + paramInt);
    this.elementData = new Object[paramInt];
  }

  public ArrayList()
  {
    this(10);
  }

  public ArrayList(Collection<? extends E> paramCollection)
  {
    this.elementData = paramCollection.toArray();
    this.size = this.elementData.length;
    if (this.elementData.getClass() == [Ljava.lang.Object.class)
      return;
    this.elementData = Arrays.copyOf(this.elementData, this.size, [Ljava.lang.Object.class);
  }

在ArrayList源碼中尽棕,頭三個(gè)方法ArrayList()均是初始化一個(gè)list的。從頭兩個(gè)方法可以看出彬伦,初始化ArrayList的時(shí)候,會創(chuàng)建一個(gè)Object數(shù)組滔悉,數(shù)組的大小可以是自己設(shè)定的一個(gè)值,也可以是系統(tǒng)默認(rèn)分配的10单绑。如果一開始傳入一個(gè)list的話回官,則會復(fù)制該list的參數(shù)到新初始化的ArrayList中。


  public void trimToSize()
  {
    this.modCount += 1;
    int i = this.elementData.length;
    if (this.size >= i)
      return;
    this.elementData = Arrays.copyOf(this.elementData, this.size);
  }

該方法是把list里的數(shù)組長度調(diào)整到原設(shè)定的長度(類中有設(shè)定了一個(gè)size來專門表示list的長度搂橙,list的size()方法返回的也正是這個(gè)size)因?yàn)槊看慰臻g不夠用時(shí)歉提,都會擴(kuò)增3/2的空間,所以list的長度和真正數(shù)組的長度是不一定相等的区转,參照下面方法苔巨。


 public void ensureCapacity(int paramInt)
  {
    this.modCount += 1;
    int i = this.elementData.length;
    if (paramInt <= i)
      return;
    Object[] arrayOfObject = this.elementData;
    int j = i * 3 / 2 + 1;
    if (j < paramInt)
      j = paramInt;
    this.elementData = Arrays.copyOf(this.elementData, j);
  }

這個(gè)方法在給list添加新元素的時(shí)候會先執(zhí)行,主要是判斷當(dāng)前l(fā)ist長度是否夠用废离,如果不夠侄泽,會新建一個(gè)數(shù)組,該數(shù)組的空間會在原數(shù)組空間基礎(chǔ)上增加3/2倍蜻韭,并把原數(shù)組的元素全部復(fù)制到新建的數(shù)組中悼尾。


  public int size()
  {
    return this.size;
  }

  public boolean isEmpty()
  {
    return this.size == 0;
  }

這兩個(gè)方法很好理解柿扣,獲取list的長度和判斷l(xiāng)ist是否為空。


public boolean contains(Object paramObject)
  {
    return indexOf(paramObject) >= 0;
  }

  public int indexOf(Object paramObject)
  {
    int i;
    if (paramObject == null)
      for (i = 0; i < this.size; ++i)
        if (this.elementData[i] == null)
          return i;
    else
      for (i = 0; i < this.size; ++i)
        if (paramObject.equals(this.elementData[i]))
          return i;
    return -1;
  }

上面的方法是用于判斷l(xiāng)ist中是否包含某個(gè)元素的闺魏,在indexOf()
中只要檢測到有一個(gè)元素是符合條件的未状,則返回該元素的位置。


  public int lastIndexOf(Object paramObject)
  {
    int i;
    if (paramObject == null)
      for (i = this.size - 1; i >= 0; --i)
        if (this.elementData[i] == null)
          return i;
    else
      for (i = this.size - 1; i >= 0; --i)
        if (paramObject.equals(this.elementData[i]))
          return i;
    return -1;
  }

該方法用于獲取一個(gè)元素在list中最后位置析桥,它是從數(shù)組的最后一個(gè)元素開始做比對的司草,所以,不管這個(gè)數(shù)組中有幾個(gè)相同的元素烹骨,都只會獲取到最后一個(gè)相同的元素翻伺,并返回它的位置。


  private void RangeCheck(int paramInt)
  {
    if (paramInt < this.size)
      return;
    throw new IndexOutOfBoundsException("Index: " + paramInt + ", Size: " + this.size);
  }
 public E get(int paramInt)
  {
    RangeCheck(paramInt);
    return this.elementData[paramInt];
  }

  public E set(int paramInt, E paramE)
  {
    RangeCheck(paramInt);
    Object localObject = this.elementData[paramInt];
    this.elementData[paramInt] = paramE;
    return localObject;
  }

get方法獲取某個(gè)位置的元素沮焕,set方法會修改某個(gè)位置的參數(shù)吨岭,并返回原參數(shù)。其中的RangeCheck()方法是用于判斷該位置是否在list長度范圍內(nèi)的峦树。


  public boolean add(E paramE)
  {
    ensureCapacity(this.size + 1);
    this.elementData[(this.size++)] = paramE;
    return true;
  }

  public void add(int paramInt, E paramE)
  {
    if ((paramInt > this.size) || (paramInt < 0))
      throw new IndexOutOfBoundsException("Index: " + paramInt + ", Size: " + this.size);
    ensureCapacity(this.size + 1);
    System.arraycopy(this.elementData, paramInt, this.elementData, paramInt + 1, this.size - paramInt);
    this.elementData[paramInt] = paramE;
    this.size += 1;
  }

add方法辣辫,用過list的應(yīng)該都很熟悉了,如果有傳入具體要放置的位置魁巩,則多了對原數(shù)組的位置移動操作急灭;沒有的話,則在數(shù)組的末尾加入該元素谷遂。


  public E remove(int paramInt)
  {
    RangeCheck(paramInt);
    this.modCount += 1;
    Object localObject = this.elementData[paramInt];
    int i = this.size - paramInt - 1;
    if (i > 0)
      System.arraycopy(this.elementData, paramInt + 1, this.elementData, paramInt, i);
    this.elementData[(--this.size)] = null;
    return localObject;
  }

  public boolean remove(Object paramObject)
  {
    int i;
    if (paramObject == null)
      for (i = 0; i < this.size; ++i)
      {
        if (this.elementData[i] != null)
          continue;
        fastRemove(i);
        return true;
      }
    else
      for (i = 0; i < this.size; ++i)
      {
        if (!paramObject.equals(this.elementData[i]))
          continue;
        fastRemove(i);
        return true;
      }
    return false;
  }

  private void fastRemove(int paramInt)
  {
    this.modCount += 1;
    int i = this.size - paramInt - 1;
    if (i > 0)
      System.arraycopy(this.elementData, paramInt + 1, this.elementData, paramInt, i);
    this.elementData[(--this.size)] = null;
  }

arrayCopy方法如下

public static void arraycopy(Object src,//源數(shù)組葬馋;
                             int srcPos,//源數(shù)組要復(fù)制的起始位置;
                             Object dest,//目的數(shù)組肾扰;
                             int destPos,//目的數(shù)組放置的起始位置畴嘶;
                             int length //復(fù)制的長度。
                             )

這幾個(gè)方法都是刪除元素的操作集晚。通過指定刪除的位置窗悯,指定刪除的元素來刪除元素;兩個(gè)刪除的方法最后都是調(diào)用了fastRemove來刪除元素的偷拔,fastRemove方法則是通過調(diào)用系統(tǒng)方法實(shí)現(xiàn)自我復(fù)制蒋院,把要刪除的元素后面的元素都向前移動一位,覆蓋掉了要刪除的元素莲绰,并把數(shù)組的最后一個(gè)元素設(shè)置為null欺旧。


  public void clear()
  {
    this.modCount += 1;
    for (int i = 0; i < this.size; ++i)
      this.elementData[i] = null;
    this.size = 0;
  }

clear方法會把數(shù)組中所有元素賦值null,并把size賦值上0蛤签。在沒有被回收內(nèi)存之前切端,數(shù)組空間也都還在。


 public boolean addAll(Collection<? extends E> paramCollection)
  {
    Object[] arrayOfObject = paramCollection.toArray();
    int i = arrayOfObject.length;
    ensureCapacity(this.size + i);
    System.arraycopy(arrayOfObject, 0, this.elementData, this.size, i);
    this.size += i;
    return i != 0;
  }

  public boolean addAll(int paramInt, Collection<? extends E> paramCollection)
  {
    if ((paramInt > this.size) || (paramInt < 0))
      throw new IndexOutOfBoundsException("Index: " + paramInt + ", Size: " + this.size);
    Object[] arrayOfObject = paramCollection.toArray();
    int i = arrayOfObject.length;
    ensureCapacity(this.size + i);
    int j = this.size - paramInt;
    if (j > 0)
      System.arraycopy(this.elementData, paramInt, this.elementData, paramInt + i, j);
    System.arraycopy(arrayOfObject, 0, this.elementData, paramInt, i);
    this.size += i;
    return i != 0;
  }

添加一個(gè)list數(shù)據(jù)到list中顷啼,第一個(gè)addAll是直接在list后面添加新的數(shù)據(jù)踏枣,第二個(gè)addAll是在指定的位置插入新增的數(shù)據(jù)昌屉。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市茵瀑,隨后出現(xiàn)的幾起案子间驮,更是在濱河造成了極大的恐慌,老刑警劉巖马昨,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件竞帽,死亡現(xiàn)場離奇詭異,居然都是意外死亡鸿捧,警方通過查閱死者的電腦和手機(jī)屹篓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來匙奴,“玉大人堆巧,你說我怎么就攤上這事∑镁” “怎么了谍肤?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長哗伯。 經(jīng)常有香客問我荒揣,道長,這世上最難降的妖魔是什么焊刹? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任系任,我火速辦了婚禮,結(jié)果婚禮上虐块,老公的妹妹穿的比我還像新娘俩滥。我一直安慰自己,他們只是感情好非凌,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布举农。 她就那樣靜靜地躺著荆针,像睡著了一般敞嗡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上航背,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天喉悴,我揣著相機(jī)與錄音,去河邊找鬼玖媚。 笑死箕肃,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的今魔。 我是一名探鬼主播勺像,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼障贸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了吟宦?” 一聲冷哼從身側(cè)響起篮洁,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎殃姓,沒想到半個(gè)月后袁波,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蜗侈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年篷牌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片踏幻。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡枷颊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出叫倍,到底是詐尸還是另有隱情偷卧,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布吆倦,位于F島的核電站听诸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蚕泽。R本人自食惡果不足惜晌梨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望须妻。 院中可真熱鬧仔蝌,春花似錦、人聲如沸荒吏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绰更。三九已至瞧挤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間儡湾,已是汗流浹背特恬。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留徐钠,地道東北人癌刽。 一個(gè)月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親显拜。 傳聞我的和親對象是個(gè)殘疾皇子衡奥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 采用數(shù)組方式存儲數(shù)據(jù),可以添加null元素远荠,此數(shù)組元素?cái)?shù)大于實(shí)際存儲的數(shù)據(jù)以便增加插入元素杰赛,都允許直接序號索引元素...
    kindol閱讀 394評論 1 0
  • ArrayList 源碼分析 不知道各位朋友,還記得開工前制定的學(xué)習(xí)目標(biāo)么矮台? 有沒有一直為了那個(gè)目標(biāo)廢寢忘食呢乏屯?繼...
    醒著的碼者閱讀 1,456評論 6 11
  • 首先看ArrayList的簽名 ArrayList特點(diǎn):隨機(jī)訪問速度快,插入和移除性能較差(數(shù)組的特點(diǎn))瘦赫;支持nu...
    Han琪閱讀 125評論 0 0
  • 【1/27/2017 周五 除夕 第149天 】 ?靜√智√勇√仁√強(qiáng)√禮 小結(jié)辰晕。 √今天我們出去游玩了,在麥當(dāng)勞...
    媽媽熊閱讀 162評論 0 0