ArrayList看完你就明白了

JDK版本:1.8


圖0:繼承結構上下文

我們進入ArrayList類查看類結構如下:


圖1:ArrayList的結構和常用

類的結構已經明確舔哪,我們以下內容就分為兩個部分,介紹構造函數(shù)和方法

構造函數(shù)

我們先看這個空構造
List<String> list = new ArrayList<String>();
//定義一個空數(shù)組
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//定義數(shù)組中的元素 transient 表明該變量不支持序列化
 transient Object[] elementData;

    /**
     * Constructs an empty list with an initial capacity of ten.
       上面的英文翻譯個人認為不對病蛉,上來的時候DEFAULTCAPACITY_EMPTY_ELEMENTDATA只是一個空數(shù)組店茶,并不涉及到數(shù)組有多大
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

ArrayList內部是由數(shù)組實現(xiàn)歧焦,elementData這個object類型的數(shù)組即為其存儲的數(shù)據(jù)結構

再看這個有參構造
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

傳入參數(shù)initialCapacity大于0時就將elementData初始化為一個initialCapacity大小的數(shù)組
傳入參數(shù)initialCapacity等于0時和無參時保持一致
傳入參數(shù)initialCapacity小于零時拋出IllegalArgumentException異常

構造函數(shù)先看到這里...比較簡單

常用方法

size()
//數(shù)組中包含的元素多少
private int size;
public int size() {
        return size;
    }

當然size的數(shù)量肯定是在add或者remove時動態(tài)修改的

add()
    /**
     * 向數(shù)組的末尾添加一個元素
     */
    public boolean add(E e) {
        //檢測是否需要并擴容 說白了就是添加一個元素之前 看看容量夠不夠
        //添加新元素是比對容器是不是夠大 你看它用size+1 多線程就會出現(xiàn)問題
        // size的值在其它線程中可變
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
//判斷元素是否是首次添加
    /**
     * 默認擴容大小.
     */
private static final int DEFAULT_CAPACITY = 10;
private void ensureCapacityInternal(int minCapacity) {
        //判斷elementData 中是否包含數(shù)據(jù)  也意為是否為首次添加
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //首次初始化數(shù)組大小時缺脉,默認給10 找不到為啥要比一下 首次添加元素 minCapacity肯定為1
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
       //此處的minCapacity為目標容量
        ensureExplicitCapacity(minCapacity); 
    }

首次添加元素嘛,首次的話也不會直接初始化容量為1的數(shù)組 而是直接來個大小為10的數(shù)組

//數(shù)組的修改次數(shù)
protected transient int modCount = 0;
//判斷容器本身容量還夠不夠
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        // 容器本身容量和目標容量做對比 判斷是否需要擴容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

目標容量和本身容量作比較劳秋,如果本身容量不夠了 就擴容

 /**
     * 擴容
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // 本人容量 首次為0
        int oldCapacity = elementData.length;
       // 擴容原則是 老容量的一半 7的一半是3
        int newCapacity = oldCapacity + (oldCapacity >> 1);
       // 擴容完后的值能不能夠用
        if (newCapacity - minCapacity < 0)
       // 不夠用 直接用目標容量
            newCapacity = minCapacity;
       //最后的容量是不是比 最大整形還大
        if (newCapacity - MAX_ARRAY_SIZE > 0)
       //如果太大最高也就給最大整型-8的值 適配其他虛擬機 為啥要-8 其他vm整型頭信息可能會有別的用
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

整個過程如下:
你想找一個盆兒盛水
你媽先不管你要多少水 先給你個盆兒 這個盆兒肯定是咱平時能盛水用的
你要往盆兒里加水
麻麻得看盆兒有沒有地兒裝仓手,如果不夠了就再找個比現(xiàn)在盆兒1.5倍的盆兒(如果還不夠就再找個肯定夠的盆兒)
看看是不是裝的水太多了胖齐,如果太多 最多給你一個缸

addAll()
 public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        //日常擴容 詳見上面
        ensureCapacityInternal(size + numNew);  // Increments modCount
        //原數(shù)組 a,開始索引0,目標數(shù)組elementData嗽冒,開始位置size(本來就比索引多1),numNew全挪
        System.arraycopy(a, 0, elementData, size, numNew);
        //新老數(shù)組的合
        size += numNew;
        return numNew != 0;
    }

兩個數(shù)組疊在一起的感覺
我有兩個棍插在洞里依次排列 | |
你有三個棍插在洞里依次排列 | | |
你想和我混成一排
System.arraycopy(a, 0, elementData, size, numNew);
a為你的那排棍
0為你想從你棍的第幾個開始 和我的混到一起
elementData為我那排棍
size 為接納你棍的起始位置
numNew為 為你預備出來幾個洞

remove()

//數(shù)組的修改次數(shù)
protected transient int modCount = 0;
public boolean remove(Object o) {
        //判斷是否list.remove(null) 遍歷數(shù)組 尋找為null的值
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                //找到被移除的值對應的索引
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
/*
     * Private remove method that skips bounds checking and does not
     * return the value removed.
     */
    private void fastRemove(int index) {
        //被修改的次數(shù)加1
        modCount++;
       //size -1 看成轉換為索引 總索引-被刪除的值所在的索引 為剩余元素條目數(shù)
        int numMoved = size - index - 1;
       //如果剩余條目數(shù)大于0 則證明刪完后需要挪后面剩下的元素
        if (numMoved > 0)
           //參數(shù)分別為:原數(shù)組呀伙、需要挪動的啟示位置、挪動后的數(shù)組添坊、需要挪到的位置区匠、挪幾個
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        //挪完后 少了個元素 最后一個肯定變成了空
        elementData[--size] = null; // clear to let GC do its work
    }

有五個孔, 圓木棍插在 孔中,依次排列了5個
| | | | |
此時想刪掉第二個,因此 找到第二個并拔出來帅腌,將第二個后面的木棍依次向前面挪
肯定剩了最后一個孔驰弄,拿土埋上

以上是數(shù)組的一些常用方法,其中的方方面面都是實際生活中的縮影

備注:ArrayList非線程安全 如果想線程安全 請使用Collections.synchronizedList(new ArrayLsit())包裝一下

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末速客,一起剝皮案震驚了整個濱河市戚篙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌溺职,老刑警劉巖岔擂,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異浪耘,居然都是意外死亡乱灵,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進店門七冲,熙熙樓的掌柜王于貴愁眉苦臉地迎上來痛倚,“玉大人,你說我怎么就攤上這事澜躺〔跷龋” “怎么了?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵掘鄙,是天一觀的道長耘戚。 經常有香客問我,道長操漠,這世上最難降的妖魔是什么收津? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮浊伙,結果婚禮上撞秋,老公的妹妹穿的比我還像新娘。我一直安慰自己吧黄,他們只是感情好部服,可當我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布唆姐。 她就那樣靜靜地躺著拗慨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赵抢,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天剧蹂,我揣著相機與錄音,去河邊找鬼烦却。 笑死宠叼,一個胖子當著我的面吹牛,可吹牛的內容都是我干的其爵。 我是一名探鬼主播冒冬,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼摩渺!你這毒婦竟也來了简烤?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤摇幻,失蹤者是張志新(化名)和其女友劉穎横侦,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绰姻,經...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡枉侧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了狂芋。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榨馁。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖帜矾,靈堂內的尸體忽然破棺而出辆影,到底是詐尸還是另有隱情,我是刑警寧澤黍特,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布蛙讥,位于F島的核電站,受9級特大地震影響灭衷,放射性物質發(fā)生泄漏次慢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一翔曲、第九天 我趴在偏房一處隱蔽的房頂上張望迫像。 院中可真熱鬧,春花似錦瞳遍、人聲如沸闻妓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽由缆。三九已至注祖,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間均唉,已是汗流浹背是晨。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留舔箭,地道東北人罩缴。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像层扶,于是被迫代替她去往敵國和親箫章。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內容