ArrayList分析及實(shí)現(xiàn)

幾個(gè)遺留的問(wèn)題:

  1. 迭代器沒(méi)加進(jìn)來(lái),還在研究中
  2. ArrayList 繼承關(guān)系沒(méi)說(shuō)明脸侥,后期專門寫一篇博客
import java.util.Collection;
/**
 * 手寫arrayList,內(nèi)部實(shí)現(xiàn):數(shù)組
 * 操作涯冠,對(duì)每個(gè)節(jié)點(diǎn)的增刪改查
 * <p>
 * 構(gòu)造方法
 */
public class ArrayList<E> {

/**
 * 集合的屬性
 * 1.大小
 * 2.節(jié)點(diǎn)
 * 3.
 */
//大小
// transient關(guān)鍵字解釋:被該關(guān)鍵字修飾的變量只保存在內(nèi)存中昔穴,不會(huì)被寫到磁盤中雪情,影響變量的生命周期
private int size;
//數(shù)組默認(rèn)長(zhǎng)度
private static final int DEFAULT_CAPACITY = 10;
//數(shù)組中的元素
private Object[] array;

//空參構(gòu)造方法
public ArrayList() {
    array = new Object[0];
}

//帶參構(gòu)造方法
public ArrayList(int capacity) {
    //如果數(shù)組長(zhǎng)度小于0湾盗,拋出異常
    if (capacity < 0) {
        throw new IllegalArgumentException("list size must be positive ,current size is " + capacity);
    }
    array = new Object[capacity];
}

//參數(shù)是一個(gè)集合的構(gòu)造方法
public ArrayList(Collection<? extends E>/*E或者E的子類*/ c) {
    //先把集合轉(zhuǎn)換成數(shù)組,然后再一個(gè)個(gè)裝到已有的數(shù)組中
    Object[] a = c.toArray();
    //三種獲取字節(jié)碼文件的方法馅巷,這里出現(xiàn)了兩種
    if (a.getClass() != Object[].class) {//由于繼承引起的多態(tài)膛虫,表明o不是E類型的數(shù)組
        //如果c不是E類型,而是E的子類钓猬,就不能簡(jiǎn)單的將c賦值給array稍刀,因?yàn)闀?huì)改變array的數(shù)據(jù)類型
        Object[] newArray = new Object[a.length];
        /**
         * 數(shù)組復(fù)制,參數(shù)說(shuō)明
         * 參數(shù)1:原數(shù)組
         * 參數(shù)2:原數(shù)組起始位置
         * 參數(shù)3:目標(biāo)數(shù)組
         * 參數(shù)4:目標(biāo)數(shù)組起始位置
         * 參數(shù)5:需要復(fù)制的數(shù)組的長(zhǎng)度
         */
        System.arraycopy(a, 0, newArray, 0, a.length);
        a = newArray;
    }
    array = a;
    size = a.length;
}

/**
 * 擴(kuò)容:為什么要擴(kuò)容:arrayList是用數(shù)組實(shí)現(xiàn)的敞曹,數(shù)組是有長(zhǎng)度的账月,當(dāng)數(shù)組的長(zhǎng)度不夠時(shí),就需要增加數(shù)組的長(zhǎng)度澳迫,即擴(kuò)容
 *
 * @param currCapacity 當(dāng)前數(shù)組的容量
 * @return 擴(kuò)容后的數(shù)組長(zhǎng)度
 */
private static int newCapacity(int currCapacity) {
    /**
     *需要增加的長(zhǎng)度
     * 舉例:如果currCapacity=4局齿,增加的長(zhǎng)度為DEFAULT_CAPACITY即10,
     *      如果currCapacity=6橄登,增加的長(zhǎng)度為currCapacity >> 1即5
     *      這樣做是為了無(wú)論在哪種情況下抓歼,保證數(shù)組的長(zhǎng)度不會(huì)出現(xiàn)太大的變化
     */
    int increment = (currCapacity < DEFAULT_CAPACITY / 2) ? DEFAULT_CAPACITY : currCapacity >> 1;
    return currCapacity + increment;
}

/**
 * 添加
 *
 * @param e 要添加的元素
 * @return 是否添加成功
 */
public boolean add(E e) {
    /**
     * 這里將array 賦值給局部變量,然后操作局部變量
     *  原因:
     *      1.線程安全考慮拢锹,防止兩個(gè)線程同時(shí)操作array出現(xiàn)bug谣妻,賦值給局部變量后,各自操作的是各自的局部變量卒稳,規(guī)避了風(fēng)險(xiǎn)
     *      2.數(shù)組是引用數(shù)據(jù)類型蹋半,操作a,就相當(dāng)于操作了array,
     *      通過(guò)局部變量就達(dá)到了修改成員變量的值的目的展哭,而且a,s使用完成后就被回收湃窍,不會(huì)占用內(nèi)存
     *  note:這里就是一個(gè)很重要的思想,先將成員變量賦值給<>局部變量</>匪傍,通過(guò)操作局部變量來(lái)達(dá)到修改成員變量值的目的
     */
    Object[] a = array;
    int s = size;
    if (s == a.length) {
        //擴(kuò)容
        int newLength = newCapacity(s);
        //創(chuàng)建新的數(shù)據(jù)
        Object[] newArray = new Object[newLength];
        //賦值
        System.arraycopy(a, 0, newArray, 0, a.length);
        //改變整個(gè)數(shù)組的長(zhǎng)度
        array = a = newArray;
    }
    //將要添加的元素加進(jìn)來(lái)
    a[s] = e;
    size = s + 1;
    return true;
}

public int size() {
    return size;
}

public boolean isEmpty() {
    return size == 0;//注意size和length的區(qū)別
}

/**
 * 根據(jù)元素查找元素對(duì)應(yīng)的下表
 * todo 這里有個(gè)疑惑:源碼中的參數(shù)是Object類型您市,但是arrayList是E類型,這里為什么要放object類型,而不是E類型
 * 先按照源碼來(lái)寫,有懂的朋友回復(fù)一下
 */
public int indexOf(Object object) {
    Object[] a = array;
    int s = size;
    if (object != null) {
        for (int i = 0; i < s; i++) {
            if (object.equals(a[i])) {
                return i;
            }
        }
    } else {
        //數(shù)組里面可以存null役衡,比如二維數(shù)組
        for (int i = 0; i < s; i++) {
            if (null == a[i]) {
                return i;
            }
        }
    }
    return -1;
}

/**
 * 某元素最后一次出現(xiàn)的角標(biāo)
 *
 * @return
 */
public int lastIndexOf(Object object) {
    Object[] a = array;
    int s = size;
    if (object != null) {
        for (int i = s; i > 0; i--) {
            if (object.equals(a[i])) {
                return i;
            }
        }
    } else {
        for (int i = s; i > 0; i--) {
            if (a[i] == null) {
                return i;
            }
        }
    }
    return -1;
}

/**
 * 刪除某個(gè)元素
 *
 * @return
 */
public E remove(int index) {
    Object[] a = array;
    int s = size;
    //邊界檢測(cè)
    if (index < 0) {
        throw new IllegalArgumentException();
    }
    if (index >= s) {//這里加不加“=”都不會(huì)報(bào)錯(cuò)茵休,因?yàn)楫?dāng)index==a.length時(shí)進(jìn)行了擴(kuò)容,存在這個(gè)角標(biāo),size角標(biāo)的元素實(shí)際上為null榕莺,我自己喜歡加上俐芯,為了統(tǒng)一記憶
        throw new ArrayIndexOutOfBoundsException();
    }
    E e = (E) a[index];
   /**
     * 為什么是s-1,而不是s
     *  舉例:size=5,index=2;
     *        此時(shí)需要將index=3和4的元素前移一個(gè)位置,此時(shí)要移動(dòng)的元素的長(zhǎng)度為2=5-1-2,即length=s-1-index;
     *        本質(zhì)上是因?yàn)閿?shù)組角標(biāo)是從0開(kāi)始導(dǎo)致的钉鸯。
     */
    System.arraycopy(a, index + 1, a, index, s - 1 - index);
    a[s] = null;//將最后一個(gè)角標(biāo)的元素置空
    s--;
    size = s;
    return e;

    /**
     * 上面幾行代碼寫法二:
     *  System.arraycopy(a, index + 1, a, index, --s  - index);
     *  a[s] = null;//將最后一個(gè)角標(biāo)的元素置空
     * size = s;
     * return e;
     */
}

public E remove(Object object) {
    int index = indexOf(object);
    E e = remove(index);
    return e;
}

public E set(int index, E e) {
    Object[] a = array;
    int s = size;
    if (index >= s) {
        throw new IndexOutOfBoundsException();
    }
    //源碼中沒(méi)加吧史,自己加的判斷
    if (index < 0) {
        throw new IllegalArgumentException();
    }
    E oldE = (E) a[index];
    a[index] = e;
    return oldE;
}

public void set(E e) {
    Object[] a = array;
    int s = size;
    if (e == null) {
        throw new IllegalArgumentException();
    }
    if (s == a.length) {
        //擴(kuò)容
        Object[] newArray = new Object[newCapacity(s)];
        System.arraycopy(a, 0, newArray, 0, a.length);
        newArray[a.length] = e;
        array = a = newArray;
        size++;
    } else {
        a[s] = e;
        size++;
    }
}

  public E get(int index) {
    Object[] a = array;
    int s = size;
    if (index >= s) {
        throw new IndexOutOfBoundsException();
    }
    E e = (E) a[index];
    return e;
  }  
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市唠雕,隨后出現(xiàn)的幾起案子贸营,更是在濱河造成了極大的恐慌,老刑警劉巖岩睁,帶你破解...
    沈念sama閱讀 212,294評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钞脂,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡捕儒,警方通過(guò)查閱死者的電腦和手機(jī)冰啃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,493評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)刘莹,“玉大人阎毅,你說(shuō)我怎么就攤上這事〉阃洌” “怎么了净薛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,790評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蒲拉。 經(jīng)常有香客問(wèn)我,道長(zhǎng)痴腌,這世上最難降的妖魔是什么雌团? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,595評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮士聪,結(jié)果婚禮上锦援,老公的妹妹穿的比我還像新娘。我一直安慰自己剥悟,他們只是感情好灵寺,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,718評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著区岗,像睡著了一般略板。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上慈缔,一...
    開(kāi)封第一講書(shū)人閱讀 49,906評(píng)論 1 290
  • 那天叮称,我揣著相機(jī)與錄音,去河邊找鬼。 笑死瓤檐,一個(gè)胖子當(dāng)著我的面吹牛赂韵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播挠蛉,決...
    沈念sama閱讀 39,053評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼祭示,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了谴古?” 一聲冷哼從身側(cè)響起质涛,我...
    開(kāi)封第一講書(shū)人閱讀 37,797評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎讥电,沒(méi)想到半個(gè)月后蹂窖,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,250評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡恩敌,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,570評(píng)論 2 327
  • 正文 我和宋清朗相戀三年瞬测,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纠炮。...
    茶點(diǎn)故事閱讀 38,711評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡月趟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出恢口,到底是詐尸還是另有隱情孝宗,我是刑警寧澤,帶...
    沈念sama閱讀 34,388評(píng)論 4 332
  • 正文 年R本政府宣布耕肩,位于F島的核電站因妇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏猿诸。R本人自食惡果不足惜婚被,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,018評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望梳虽。 院中可真熱鬧址芯,春花似錦、人聲如沸窜觉。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,796評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)禀挫。三九已至旬陡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間特咆,已是汗流浹背季惩。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,023評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工录粱, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人画拾。 一個(gè)月前我還...
    沈念sama閱讀 46,461評(píng)論 2 360
  • 正文 我出身青樓啥繁,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親青抛。 傳聞我的和親對(duì)象是個(gè)殘疾皇子旗闽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,595評(píng)論 2 350

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