- 持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第24天,点击查看活动详情
构造方法
ArrayList有三个构造方法,默认的无参构造跟传递数值参数和Collection类参数的有参构造
无参构造
无参构造方法下会指向一个默认的空数组,所以并不是new的时候就分配了空间
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
数值参数构造方法
传参为数值的构造方法在参数大于0的情况下会创建一个对应长度的数组,如果等于零会指向一个静态常量的空数组,剩下的可能就是小于0,则会抛异常
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
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);
}
}
异常
Collection构造方法
这个构造方法可以传递所有Collection及它下面的子类,有560个
在这个构造方法里会先将传递的参数Collection转为对象数组,
Object[] a = c.toArray();
然后判断新数组大小是否等于0,
if ((size = a.length) != 0)
不等于0的话会判断Collection是不是ArrayList,如果是ArrayList就将数组直接指向新数组,否则就需要对Collection进行复制操作生成一个ArrayList对象来达到转换的目的。
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
elementData = Arrays.copyOf(a, size, Object[].class);
}
等于0跟上面的情况一样,指向一个静态常量的空数组对象
// replace with empty array.
elementData = EMPTY_ELEMENTDATA;
完整代码
add
在ArrayList进行添加操作时会先对数组进行初始化或者扩容
获取数组长度
ensureCapacityInternal(size + 1); // Increments modCount!!
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
注意下面的这个方法,这个方法是提供数组长度的方法,在进行add操作的时候如果当前数组为空数组会比较传参的长度取最大值,这样就可以说ArrayList无参构造方法创建的时候并没有对长度初始化,而是在进行add操作的时候进行的长度初始化,默认值为10,不为空的情况直接返回传入参数的值
calculateCapacity(elementData, minCapacity)
private static final int DEFAULT_CAPACITY = 10;
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
增加modCount并判断是否扩容
calculateCapacity这个方法就是增加modCount的操作跟判断是否需要扩容的逻辑了
modCount是一个记录List对象被修改多少次的值
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
modCount++不用看,就是增加一下修改次数,看一下下面的判断逻辑,如果传入的需要更改的数组长度减去当前数组的长度还大于0就需要扩容了
扩容逻辑
运算逻辑是先拿当前的长度得到旧长度,然后将当前数组长度的1.5倍当做新长度,这里使用的位运算
int newCapacity = oldCapacity + (oldCapacity >> 1);
得到新长度后判断新长度减去传递的参数长度小于0,小于0的话直接用参数长度即可,不小于判断是不是比设置的最大长度大,查看达到最大数值的判断逻辑
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
如果传入参数小于0抛异常这是兜底性校验,然后三元表达式判断传入参数值是否大于最大列表长度,最大列表长度是Integer.MAX_VALUE - 8 如果大于只能上Integer.MAX_VALUE否则就还是MAX_ARRAY_SIZE
完成后按长度进行列表扩容