ArrayList源码解析之add()方法解析(jdk8)

这几天看了一下ArrayList的源码,下面就把我所学到的和大家分享一下。上代码

在源码中,add(E e)方法,先执行的是ensureCapacityInternal()方法,这个方法是进行扩容判断,如果需要扩容就先进行扩容操作。

	/**
     * 新增元素操作
     */
    public boolean add(E e) {
        /** 确定是否需要扩容,如果需要,则进行扩容操作. size表示当前list的大小,size+1就是list所需要的空间大小 */
        ensureCapacityInternal(size + 1);  // Increments modCount!!

        // eg1:size=0,elementData[0]="a1",然后a自增为1
        elementData[size++] = e;
        return true;
    }

ensureCapacityInternal(),先由calculateCapacity方法计算出所需要的最小空间大小,再由ensureExplicitCapacity方法来判断是否需要扩容,计算应该扩容成多大,扩容方法就在ensureExplicitCapacity方法中.

	/**
     * minCapacity表示list所需要的最小空间,比如当前list里面放了5个数,需要的空间大小就是5,你执行add方法添加一个数,需要的空间就是6了,需要加一
     * @param minCapacity
     */
    private void ensureCapacityInternal(int minCapacity) {
        // eg1:第一次新增元素,calculateCapacity方法返回值为DEFAULT_CAPACITY=10
        // 扩容操作就在这个方法里面, elementData就是存放数据的数组,minCapacity就是存放数据所需的最小地址
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

calculateCapacity(elementData, minCapacity) 计算出存放元素需要的最小空间

	private static int calculateCapacity(Object[] elementData, int minCapacity) {
		// DEFAULTCAPACITY_EMPTY_ELEMENTDATA为常量 {} ,判断elementData是不是初始状态,也就是数组大小为0的时候,是true的话,表示这是第一次扩容
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { 
        // 初始状态扩容,第一次扩容默认是变成10,但是如果所需要的最小空间大于10,第一次扩容就不是变成10了。比如你直接调用addAll()方法,传入一个大小大于10的list进去.
            return Math.max(DEFAULT_CAPACITY, minCapacity); // eg1:满足if判断,DEFAULT_CAPACITY=10
        }
        return minCapacity;
    }

执行ensureExplicitCapacity方法,判断是否需要扩容

	private void ensureExplicitCapacity(int minCapacity) {
        // eg1: modCount++后,modCount=1
        modCount++; // 并发相关

        /** 前面的方法都是在计算需要的最小空间,这一步才是关键,判断需要的最小空间是不是大于当前数组大小,如果是那就得扩容数组,这样才能放的下元素 */
        if (minCapacity - elementData.length > 0) { // eg1:10-0=10,满足扩容需求
            // eg1:minCapacity=10
            grow(minCapacity); // 扩容方法
        }
    }

grow(minCapacity);扩容方法,计算出数组应该扩容之后的大小

	// minCapacity需要的最小空间大小
	private void grow(int minCapacity) {

        /** 当前数组elementData的长度*/
        int oldCapacity = elementData.length; // eg1:oldCapacity=0

        /**
         * oldCapacity >> 1 相当于除以2(这是右移)
         * 000100 >> 1 = 000010
         * 000100 << 1 = 001000
         */
        /** 新增oldCapacity的一半整数长度作为newCapacity的额外增长长度 */
		// 得到新数组长度
        int newCapacity = oldCapacity + (oldCapacity >> 1); // eg1:newCapacity=0+(0>>1)=0

        /** 如果新的长度newCapacity依然无法满足需要的最小扩容量minCapacity,则新的扩容长度为minCapacity */
        if (newCapacity - minCapacity < 0) {
            // eg1:newCapacity=10
            newCapacity = minCapacity;
        }

        /** 新的扩容长度newCapacity超出了最大的数组长度MAX_ARRAY_SIZE huge:巨大的 */
        if (newCapacity - MAX_ARRAY_SIZE > 0) {
            newCapacity = hugeCapacity(minCapacity);
        }

		// 调用Arrays工具类,创建一个指定大小的数组,再把元素放到新数组上
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

add,ensureCapacityInternal()指定完成之后,直接把元素加入到数组,返回true.


public boolean add(E e) {
        /** 确定是否需要扩容,如果需要,则进行扩容操作. size表示当前list的大小,size+1就是list所需要的空间大小 */
        ensureCapacityInternal(size + 1);  // Increments modCount!!
		
        // eg1:size=0,elementData[0]="a1",然后a自增为1
        elementData[size++] = e;
        return true;
    }

这些步骤,我认为中的来说就是。

  1. 先确定存放这些元素所需要的最小空间(数组为初始化状态且需要的最小空间小于10,直接将最小空间设为10)
  2. 判断是否需要扩容,如果需要的最小空间数小于当前数组长度,那就可以放的下这些元素,便不需要扩容
    2.1 如果需要扩容: 然后计算出应该将数组扩容成多大,根据大小创建新数组,将元素放到新数组
    2.2 不需要扩容,数组不变
  3. 加新元素加入到数组,返回true
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值