前言
很开心你能看我的博客。我是正在学习的菜鸟,如果你觉得我的博客对你收益颇多,请留下个脚印。
正文
废话不多直接上代码,分析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()方法。
如果有错误的地方,还请大家指出来!!谢谢观看!!