ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ArrayList详解

2020-10-27 10:03:35  阅读:178  来源: 互联网

标签:int ArrayList elementData minCapacity 数组 详解 size


本文将结合java源码详细介绍ArrayList的底层实现:

​ 首先ArrayList的底层是一个Object类型的数组,当执行new ArrayList()的时候,数组的长度是0,当对象调用add()函数的时候,会创建一个初始长度为10的数组。在ArrayList里面有两个构造函数,无参的构造函数会创建一个默认长度为10的数组,当使用有参的构造函数时,若传入的参数大于0,则创建一个对应参数大小的数组,若等于0则创建一个默认长度10的数组,否则报出一个IlleglArgumentException的异常。

private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.
     */
private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

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);
        }
}

public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

当调用add函数的时候,源代码如下。不要索引的add函数会直接将元素加在当前arrayList对象的末尾,会首先使用ensureCapacityInternal函数,会判断此时的ArrayList对象是否需要进行扩容,会比较当前的容量和minCapacity的值,minCapacity代表的是当前对象加入了当前元素个数,当加入之前的数组为空时,则minCapacity记为起始默认的数组长度10,否则记为加入之前对象中元素的个数加一。

若此时的minCapacity大于当前数组的长度是,则使用grow()函数对数组进行扩容,然后对扩容后的数组给size++索引位置赋值给添加元素,否者直接对size++出的直接赋值即可。

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

public void add(int index, E element) {
    rangeCheckForAdd(index);
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    System.arraycopy(elementData, index, elementData, index + 1,size - index);
    elementData[index] = element;
    size++;
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

此时的grow函数才是真正地对ArrayList对象进行扩容,若当前的minCapacity大于当前数组长度的1.5则需要新的数组需要扩容到之前的1.5倍,否则需要新数组长度等于minCapacity长度大小。(什么情况下会发生呢?)同时在grow函数里面还需要和ArrayList可以的最大size(MAX_ARRAY_SiZE)比较,如果此时的minCapacity小于零会报OOM错误,否则会将更新的长度赋值为Integer.MAX_VLUE长度。然后使用Arrays里面的copyOf进行复制数组。

private void grow(int minCapacity) {
    // overflow-conscious code 这是为了防止int溢出所作的处理
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    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);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;
}

Arrays里面的copyOf函数会重新创建一个数组长度为参数的数组,将原来数组里面的元素按照原来的位置一次存入新的数组。

标签:int,ArrayList,elementData,minCapacity,数组,详解,size
来源: https://www.cnblogs.com/bevishe/p/13883274.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有