java1.8之ArrayList集合源码解析

成员变量源码

// 默认的初始化容量
private static final int DEFAULT_CAPACITY = 10;

// 用于空实例的共享空数组实例
private static final Object[] EMPTY_ELEMENTDATA = {};

//用于默认大小的空实例的共享空数组实例。我们将其与空元素数据区分开来,以了解何时充气添加第一个元素。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
 * 存储ArrayList元素的数组缓冲区。ArrayList的容量是这个数组缓冲区的长度。当添加第一个元素时,任何 
 * 带//有elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空ArrayList都将扩展为 
 *  DEFAULT_CAPACITY。
*/
transient Object[] elementData;  // 非私有以简化嵌套类访问
/**
 * ArrayList的大小(它包含的元素的数量)
*/
private int size;

构造方法1:

第一种构造方法:
/**
     * 构造具有指定初始容量的list
     *
     * @param  list的初始化容量
     * @throws 如果指定的初始容量是负数就抛出IllegalArgumentException异常
     */
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
               // 如果初始化容量大于0则创建一个容量为initialCapacity的动态数组
            this.elementData = new Object[initialCapacity];

        } else if (initialCapacity == 0) {
                // 如果初始化容量等于0则设置为初始化的成员变量EMPTY_ELEMENTDATA空数组
            this.elementData = EMPTY_ELEMENTDATA;

        } else {
                // 如果小于零则抛出非法参数异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }


第二种构造方法:

/**
  * 源码注释:创建一个初始化为10的list
  * 但是DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个空的数组,这就是1.8的不点,其实它是在调用add 
  * 方法时添加第一个元素的时候才将list集合的初始化容量改为了10,一开始创建集合的时候它的初始化 
  * 容量是0
*/
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }


第三种构造方法:
/**
     *构造包含指定的集合
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

我们来看看add()方法:到底是不是在第一次添加元素的时候才完成的初始化容量;


    public boolean add(E e) {

        // 确定内部容量。size代表的是list中已有的元素length
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    *此方法是上面方法中calculateCapacity的实现方法,在此方法中,if判断只有在第二种构造方法new 
     ArrayList()才能判断通过,通过后初识化为(DEFAULT_CAPACITY = 10)

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
    // 否则返回
        return minCapacity;
    }

    
    *此方法是上面方法中ensureExplicitCapacity的实现方法

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

        // 这里就是判断需不需要扩容,如果当前集合长度大于底层数组长度则进行扩容,进而调用下面的 
        // grow()方法
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    
// grow()方法的实现
private void grow(int minCapacity) {
        // 把数组长度赋值给老的容量
        int oldCapacity = elementData.length;

        // 新的数组容量 = 老的数组容量的1.5倍  oldCapacity >>1 相当于除以2
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        
        // 如果新的容量小于传入的参数容量,则新的容量等于传入的参数容量
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        
        // 如果新的容量大于数组容纳的最大元素个数 MAX_ARRAY_SIZE 2^{31}-1-8
        // 那么在判断传入的容量是否大于数组容纳的最大元素个数,如果大于的话,那么新的数组容量则等于
        // Integer.MAX_VALUE;否则等于 MAX_ARRAY_SIZE

        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

这里有3个判断:

if (newCapacity - minCapacity < 0)
if (newCapacity - MAX_ARRAY_SIZE > 0)
以及hugeCapacity(minCapacity);函数中的:
(minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
意义为:当重新计算的容量(x1.5那个计算)小于传入要求容量参数,那么新的容量则按照新传入的容量为基准;

当传入容量参数太大,大到超过了数组的容量限定值2^{31}-1-8却又小于整数限定值 2^{31}-1,那么新的数组容量以整数限定值 2^{31}-1为准,但是当传入的容量参数不大于数组的容量限定值时,以容量限定值2^{31}-1-8为准;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值