jdk ArrayList源碼解讀

java jdk是如何實現(xiàn)ArrayList的第献?

ArrayList的實現(xiàn)很簡單钢坦,總的來說,就是arraylist內(nèi)置了一個Object類型的數(shù)組比搭,當(dāng)插入或刪除數(shù)據(jù)時冠跷,都操作這個內(nèi)置數(shù)組array。當(dāng)用戶想new的ArrayList大于內(nèi)置數(shù)組時敢辩,會在后面串一個數(shù)組蔽莱,具體數(shù)組怎么遞增看下文。

1. ArrayList中的屬性

    //數(shù)組每次增加長度時最小增量(具體每次增加時戚长,增量不一定是MIN_CAPACITY_INCREMENT盗冷,有一定的策略)
    private static final int MIN_CAPACITY_INCREMENT = 12;
    
    //ArrayList的長度
    int size;
    
    //數(shù)組
    transient Object[] array; 

2. 構(gòu)造函數(shù)

我們先來看看構(gòu)造函數(shù)怎么實現(xiàn)的。

2.1 不指定大小

像這樣定義:

ArrayList arrayList = new ArrayList();

直接創(chuàng)建一個大小為0的ArrayList實例同廉。

public ArrayList() {
     array = EmptyArray.OBJECT;
 }
 

2.2 指定int類型的大幸翘恰(容量)

像這樣定義:

ArrayList arrayList = new ArrayList(10);

如果指定的容量大小capacity為0,則只創(chuàng)建一個容量為0的ArrayList實例迫肖,否則锅劝,直接new一個指定大小的Object類型的數(shù)組。

public ArrayList(int capacity) {
if (capacity < 0) {
   throw new IllegalArgumentException("capacity < 0: " + capacity);
 }
 array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]);
}
 

2.3 創(chuàng)建一個包含指定Collection的list

像這樣定義:

ArrayList arrayList = new ArrayList(Collection collection);

直接把Collection轉(zhuǎn)換為數(shù)組蟆湖,并復(fù)制給ArrayList的數(shù)組array故爵。具體實現(xiàn)如下:

private static int newCapacity(int currentCapacity) {
    int increment = (currentCapacity < (MIN_CAPACITY_INCREMENT / 2) ?
            MIN_CAPACITY_INCREMENT : currentCapacity >> 1);
    return currentCapacity + increment;
}

3 增量的確定

3.1 插入數(shù)據(jù)時,ArrayList內(nèi)置數(shù)組增量的確定

ArrayList插入涉及到數(shù)組增量的問題隅津,即插入一個數(shù)或一組數(shù)時诬垂,ArrayList內(nèi)置的數(shù)組該如何增長劲室?如果頻繁增長,既浪費時間又會使內(nèi)存碎片化结窘;可如果每次增量很大很洋,如每插入數(shù)據(jù)內(nèi)置數(shù)組就增加很大的容量值,那么會導(dǎo)致很多空間浪費隧枫。 jdk有一個方法提供了具體策略:

private static int newCapacity(int currentCapacity) {
    int increment = (currentCapacity < (MIN_CAPACITY_INCREMENT / 2) ?
            MIN_CAPACITY_INCREMENT : currentCapacity >> 1);
    return currentCapacity + increment;
}

如果指定增量currentCapacity小于12/2=6喉磁,則增量為12;否則增量為currentCapacity/2.

注:currentCapacity >> 1 即為currentCapacity/2.如:

0000 0111(7)>> 1 右移一位變?yōu)?0000 0011(3)官脓。

0000 1100(12)>> 1 右移一位變?yōu)?0000 0110(6)协怒。

3.2 在index位置插入一個數(shù)object

我們來看一下方法,add(int index, E object),在index位置插入一個Object類型的數(shù)卑笨。

@Override 
public void add(int index, E object) {
    Object[] a = array;
    int s = size;
    if (index > s || index < 0) {
        throwIndexOutOfBoundsException(index, s);
    }

    if (s < a.length) {
        System.arraycopy(a, index, a, index + 1, s - index);
    } else {
        // assert s == a.length;
        Object[] newArray = new Object[newCapacity(s)];
        System.arraycopy(a, 0, newArray, 0, index);
        System.arraycopy(a, index, newArray, index + 1, s - index);
        array = a = newArray;
    }
    a[index] = object;
    size = s + 1;
    //父類AbstractList的一個屬性斤讥,記錄list改變了幾項
    modCount++;
}

其實就是

  1. 先根據(jù)newCapacity方法獲取到數(shù)組增量,

  2. 然后new一個臨時數(shù)組newArray湾趾,先把當(dāng)前數(shù)組array從[0,index]都copy給newArray的[0,index],

  3. 然后把array從 [index,s](數(shù)組末尾)copy給newArray的[index+1,s+1]派草,這樣全部數(shù)組就復(fù)制過來了搀缠,然后把newArray copy給array;

  4. 最后令array[index+1]為新插入的值object近迁,size+1艺普。

3.3 在index位置插入一個collection

這種情況下增量是多少呢?

注意:ArrayList并不是直接增加collection.length()的長度鉴竭,而是通過newCapacity方法來計算增量歧譬,傳入的參數(shù)是 當(dāng)前數(shù)組的長度(size+newSize).
其中 newSize為新數(shù)組newArray(collection.toArray())的長度.

前面我們說過,如果一次增量過小搏存,會造成頻繁增加數(shù)組瑰步,這樣既浪費時間,又會損耗性能璧眠。

代碼如下:

@Override
public boolean addAll(int index, Collection<? extends E> collection) {
    int s = size;
    if (index > s || index < 0) {
        throwIndexOutOfBoundsException(index, s);
    }
    Object[] newPart = collection.toArray();
    int newPartSize = newPart.length;
    if (newPartSize == 0) {
        return false;
    }
    Object[] a = array;
    int newSize = s + newPartSize; // If add overflows, arraycopy will fail
    if (newSize <= a.length) {
         System.arraycopy(a, index, a, index + newPartSize, s - index);
    } else {
        int newCapacity = newCapacity(newSize - 1);  // ~33% growth room
        Object[] newArray = new Object[newCapacity];
        System.arraycopy(a, 0, newArray, 0, index);
        System.arraycopy(a, index, newArray, index + newPartSize, s-index);
        array = a = newArray;
    }
    System.arraycopy(newPart, 0, a, index, newPartSize);
    size = newSize;
    modCount++;
    return true;
}

4. remove方法

4.1 remove(int index)

先把index后面的值全部向前移一位缩焦,然后把最后一位a[s]置為空。

@Override 
    public E remove(int index) {
    Object[] a = array;
    int s = size;
    if (index >= s) {
        throwIndexOutOfBoundsException(index, s);
    }
    @SuppressWarnings("unchecked") E result = (E) a[index];
    //核心代碼
    //把數(shù)組a[index+1,s]復(fù)制給數(shù)組a[index,s-1]
    System.arraycop
    y(a, index + 1, a, index, --s - index);
    //數(shù)組最后以為置空
    a[s] = null;  // Prevent memory leak
    size = s;
    modCount++;
    return result;
}

4.2 clean方法

把數(shù)組全部置空责静。

@Override public void clear() {
    if (size != 0) {
        Arrays.fill(array, 0, size, null);
        size = 0;
        modCount++;
    }
}

public static void fill(Object[] array, int start, int end, Object value) {
    Arrays.checkStartAndEnd(array.length, start, end);
    for (int i = start; i < end; i++) {
        array[i] = value;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末袁滥,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子灾螃,更是在濱河造成了極大的恐慌题翻,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腰鬼,死亡現(xiàn)場離奇詭異嵌赠,居然都是意外死亡塑荒,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進(jìn)店門猾普,熙熙樓的掌柜王于貴愁眉苦臉地迎上來袜炕,“玉大人,你說我怎么就攤上這事初家≠司剑” “怎么了?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵溜在,是天一觀的道長陌知。 經(jīng)常有香客問我,道長掖肋,這世上最難降的妖魔是什么仆葡? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮志笼,結(jié)果婚禮上沿盅,老公的妹妹穿的比我還像新娘。我一直安慰自己纫溃,他們只是感情好腰涧,可當(dāng)我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著紊浩,像睡著了一般窖铡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上坊谁,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天费彼,我揣著相機與錄音,去河邊找鬼口芍。 笑死盈罐,一個胖子當(dāng)著我的面吹牛抓艳,可吹牛的內(nèi)容都是我干的麸澜。 我是一名探鬼主播坛梁,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼膘融!你這毒婦竟也來了芙粱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤氧映,失蹤者是張志新(化名)和其女友劉穎春畔,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡律姨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年振峻,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片择份。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡扣孟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出荣赶,到底是詐尸還是另有隱情凤价,我是刑警寧澤,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布拔创,位于F島的核電站利诺,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏剩燥。R本人自食惡果不足惜慢逾,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望灭红。 院中可真熱鬧侣滩,春花似錦、人聲如沸变擒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赁项。三九已至,卻和暖如春澈段,著一層夾襖步出監(jiān)牢的瞬間悠菜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工败富, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留悔醋,地道東北人。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓兽叮,卻偏偏與公主長得像芬骄,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子鹦聪,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,851評論 2 361

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