01_ArrayList核心源码剖析

一、基本原理

  1. 数组的长度是固定的,java里面数组都是定长数组,如果不停的往ArrayList里面塞入这个数据,此时元素数量超过了初始大小,此时就会发生一个数组的扩容,就会搞一个更大的数组,把以前的数组拷贝到新的数组里面去
  2. 缺点一、这个数组扩容+元素拷贝的过程,相对来说会慢一些. 所以,不要频繁的往arralist里面去塞数据,导致他频繁的数组扩容,避免扩容的时候较差的性能影响了系统的运行
  3. 缺点二、数组来实现,数组你要是往数组的中间加一个元素,是不是要把数组中那个新增元素后面的元素全部往后面挪动一位,所以说,如果你是往ArrayList中间插入一个元素,性能比较差,会导致他后面的大量的元素挪动一个位置
  4. 优点一、基于数组来实现,非常适合随机读,你可以随机的去读数组中的某个元素,list.get(10),相当于是在获取第11个元素,这个随机读的性能是比较高的,随机读,list.get(2),list.get(20),随机读list里任何一个元素
  5. 为什么基于数组的ArrayList随机读写会很快,而插入性能较低,因为数组是基于内存里连续的空间,只要根据Index+offset就可以计算出我们想访问的那个元素在内存中的地址

源码

代码片段一、

public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    // 代码片段二、
    list.add("zhangsan");
    list.add("lisi");
    list.add("wuwang");
    System.out.println(list.toString());
    System.out.println(list.toString());
    // 代码片段六、
    list.get(2);
    // 代码片段七、这里其实是向集合中的index为1的地方,插入一个新的元素
    list.add(1,"zhaoliu");
}

代码片段二、

/**
 * Appends the specified element to the end of this list.
 *
 * @param e element to be appended to this list
 * @return <tt>true</tt> (as specified by {@link Collection#add})
 */
public boolean add(E e) {
    // 这里是在计算当前元素应该放在list中的index索引,代码片段三、
    // 这里的size其实就是当前集合的大小,这里要和capacity区分开
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    // 将当前元素放入到集合中,index=size++
    elementData[size++] = e;
    return true;
}

代码片段三、

private void ensureCapacityInternal(int minCapacity) {
    // 代码片段四、
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

// 通过代码片段四,第一次进来,minCapacity的值为10
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;


    // overflow-conscious code
    // 如果minCapacity大于集合现在的大小的话,就会走k扩容逻辑
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

代码片段四、

/**
* elementData:代表当前集合的底层数组
* minCapacity:当前数组的大小+1
* 所以第一次调用list的add()方法的时候,elementData是空的,minCapacity为1
* 返回DEFAULT_CAPACITY,集合的初始化大小 10
*/
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}

代码片段五、

/**
 * Increases the capacity to ensure that it can hold at least the
 * number of elements specified by the minimum capacity argument.
 *
 * @param minCapacity the desired minimum capacity
 */
private void grow(int minCapacity) {
    // overflow-conscious code
    // 集合现在的大小
    int oldCapacity = elementData.length;
    // 扩容逻辑就是:oldCapacity(老的大小) + oldCapacity/ 2
    // 比如原来大小10,现在扩容,就是10 + 10/2 = 15
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 如果新的仓位15大于minCapacity
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    // 这里进行数组拷贝,完成老数组到新数组的拷贝
    elementData = Arrays.copyOf(elementData, newCapacity);
}

代码片段六、

/**
 * Returns the element at the specified position in this list.
 *
 * @param  index index of the element to return
 * @return the element at the specified position in this list
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public E get(int index) {
    // 如下面代码,如果index超过了size,就会报出来一个数组越界异常
    rangeCheck(index);

    // 返回index下的元素,所以,集合的读是很快的
    return elementData(index);
}

/**
 * Checks if the given index is in range.  If not, throws an appropriate
 * runtime exception.  This method does *not* check if the index is
 * negative: It is always used immediately prior to an array access,
 * which throws an ArrayIndexOutOfBoundsException if index is negative.
 */
private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

代码片段七、

/**
* 在指定位置插入一个新的元素,然后指定位置以后的元素进行重新排序
 * Inserts the specified element at the specified position in this
 * list. Shifts the element currently at that position (if any) and
 * any subsequent elements to the right (adds one to their indices).
 *
 * @param index index at which the specified element is to be inserted
 * @param element element to be inserted
 * @throws IndexOutOfBoundsException {@inheritDoc}
 */
public void add(int index, E element) {
     // 检查index是否越界,越界则抛出角标越界异常
    rangeCheckForAdd(index);

    // 代码片段四中的检查是否需要扩容
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    // 这里的数组拷贝,然后index后面的元素向后移动
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    // 将新的元素放入到指定index中
    elementData[index] = element;
    size++;
}

/**
 * A version of rangeCheck used by add and addAll.
 */
private void rangeCheckForAdd(int index) {
    // 检查index是否越界
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}

三、总结

  1. 其实对于大部分Java的程序员来说,ArrayList的基本原理都没啥问题,但是我们为什么还要继续分析ArrayList的源码呢,主要是,随着我们工作年限的增加,在去面试的话,基本上都是往死里问,所以对于基础的集合,我们还是很有必要来分析一下他的源码
  2. 我们仅仅是研究一下核心源码,如果对ArrzyList中1500行左右的源码全部剖析的话,首先我们肯定记不住这么多,其次还可能忽略核心功能,如果对于核心功能已经了解的话,其他的API其实都不难的
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容