ArrayList源码步步分析--------add的时候都发生了什么?

前言

很开心你能看我的博客。我是正在学习的菜鸟,如果你觉得我的博客对你收益颇多,请留下个脚印。

正文

废话不多直接上代码,分析ArrayList源码之前你要先了解它的属性
JDK版本1.8

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
//序列化版本号
private static final long serialVersionUID = 8683452581122892189L;
//默认初始化容量10
private static final int DEFAULT_CAPACITY = 10;

//空数组 用户如果指定大小为0创建的就是这个数组 可以看下面的构造方法
private static final Object[] EMPTY_ELEMENTDATA = {};

/**用户不指定大小 创建的是这个数组  可以看下面的构造方法
 *只要这个数组添加数据就会变成容量为10的数组
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

//不可序列化的数组 用来存储ArrayList的数据
transient Object[] elementData;

//ArrayList数据的长度
private int size;
//有参 对应上面 这里代码简单就不做分析
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方法都发生了什么。

ArrayList arrayList = new ArrayList();

arrayList.add("1");

首先我们模拟已经创建了一个没指定大小的ArrayList 进入add方法

/**
 *这是我们的add方法 返回值为boolean 
 *参数E 为ArrayList<E>泛型 如果没指定默认是Object
 */
public boolean add(E e) {
		//确保容量的方法
        ensureCapacityInternal(size + 1);
        elementData[size++] = e;
        return true;
}

再调用了add方法之后 我们首先计入ensureCapacityInternal()方法,这是一个确保容量的方法。size变量为0+1目前我们没有任何数据),我们进去看看有什么。

private void ensureCapacityInternal(int minCapacity) {
		//minCapacity 为1  elementData为null
		//因为我们目前没有数据
        ensureExplicitCapacity(calculateCapacity(elementData,
        minCapacity));
}

又调用了calculateCapacity()方法,此时我们传进去的参数为null,1。我们来看看calculateCapacity()方法。

private static int calculateCapacity(Object[] elementData, int
minCapacity) {
//由于我们没有指定大小 
//创建的数组就是DEFAULTCAPACITY_EMPTY_ELEMENTDATA 进入if方法
	 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
	 //返回两个数之间最大的数,也就是返回了10
	       return Math.max(DEFAULT_CAPACITY, minCapacity);
	   }
	 //如果是自己指定大小,直接返回数据长度
	 return minCapacity;
}

现在我们返回之前的方法,我们的返回值是默认容量10。

private void ensureCapacityInternal(int minCapacity) {
		//现在相当于ensureExplicitCapacity(10)
        ensureExplicitCapacity(calculateCapacity(elementData,
        minCapacity));
}

进入ensureExplicitCapacity方法

private void ensureExplicitCapacity(int minCapacity) {
		//这个属性代表类似于修改次数+1
        modCount++;

     /**这里的判断 数据实际长度-数组容量>0还需要检测一下容量是否够
       *如果<0说明数据的小于容量 可以直接放进去
       *elementData.length实际代表着容量的长度
       *此时这里minCapacity 为10,此时elementData.length为0
       */
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

我们先看看ArrayList的最大容量是多少,在进入grow()方法。

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

Integer的最大值:2147483647 - 8 = 2147483639

private void grow(int minCapacity) {
    //首先将容量赋值给oldCapacity,这里我们暂时是0
     int oldCapacity = elementData.length;
    //新的容量计算过后也是0,oldCapacity >> 1的意思是/2的一次幂
    //如果>>2  就是/2的2次幂
    //所以这里的意思就是老的容量扩容1.5倍 
    //由于我们老的容量是0,所以这里是0.但如果有容量这里就被扩容了
     int newCapacity = oldCapacity + (oldCapacity >> 1);
     //之后判断扩容后的容量是否够需求
     //0-10<0 我们进入这个逻辑 newCapacity 变成了10
     if (newCapacity - minCapacity < 0)
         newCapacity = minCapacity;
     //这里判断是否超出最大取值
     //超出的话hugeCapacity()方法就会返回Integer的最大值
     if (newCapacity - MAX_ARRAY_SIZE > 0)
         newCapacity = hugeCapacity(minCapacity);
     //将旧的数据和新的容量移动到新创建的数组返回,最大的性能消耗就在这
     elementData = Arrays.copyOf(elementData, newCapacity);
}

最后我们带着新创建的elementData 返回add方法

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

相信这里大家都能看懂了size++,elementData【0】= e
运行完后size变成1。

好了add的源码我们分析到这,其实还有个有参的add方法,你只要看懂这个add方法,那个代码自然很容易懂,增删改查也是信手拈来。
优化:ArrayList 最好在创建时给定大小是最好的,因为不需要执行grow()方法。

如果有错误的地方,还请大家指出来!!谢谢观看!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值