啥也不说了,直接撸源码:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
从上述代码中我们可以看出继承了AbstractList
即List
接口,实现了RandomAccess
,Cloneable
两个接口,其中RandomAccess
接口中没有任何方法,他只是一个标识,说明实现该接口的类是一个可以随机访问的类方便查询,Cloneable
是标记型的接口,它们内部都没有方法和属性,实现Cloneable
来表示该对象能被克隆,能使用Object.clone()
方法。如果没有实现 Cloneable
的类对象调用clone()
就会抛出CloneNotSupportedException
。
今天我们重点看的是ArrayList
中的add
方法:
1.先说几个关键的几个全局变量:
//用于定于初始的大小
private static final int DEFAULT_CAPACITY = 10;
//默认初始容量。
private static final Object[] EMPTY_ELEMENTDATA = {
};
//用于空实例的共享空数组实例
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
};
//操作数组
transient Object[] elementData;
//ArrayList的大小(它包含的元素数)
private int size;
2.构造器
//给定初始大小
public ArrayList(int initialCapacity) {
//判断initialCapacity是否大于0
if (initialCapacity > 0) {
//如果大于0,则将initialCapacity作为ArrayList的初始大小
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//如果等于0则将赋值一个空数组作为ArrayList的初始容量
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
//在使用无参构造时,默认给ArrayList初始容量为0
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
从上面的两个构造器可以看出ArrayList
底层实现是数组,并且在不给定初始大小时,默认大小为0。
3.添加方法add()
public boolean add(E e) {
//size记录的是ArrayList的大小(它包含的元素数),并加让当前seiz+1
ensureCapacityInternal(size + 1);
//对组大小进行判断或扩容完成后,将新的元素添加大最后一个位置
elementData[size++] = e;
//返回true,表示添加成功
return true;
}
ArrayList
在调用add
方法添加元素时,首先会调用ensureCapacityInternal(size + 1)
方法,对数组大小进行判断及扩容如下分析:
//minCapacity为实际元素个+1的大小
private void ensureCapacityInternal(int minCapacity) {
// elementData为容纳元素的数组
//minCapacity为实际元素个+1的大小
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
发现ensureCapacityInternal
方法内部又调用了ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
方法,
在ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
中他先调用的是calculateCapacity(elementData, minCapacity)
方法:
// elementData为容纳元素的数组
//minCapacity为实际元素个+1的大小
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//判断当数组是否为空数组,如果 elementData为空说明刚初始化的新实例对象,
//准备添加一个元素
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//给初始化新实例分配容量:10
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
//如果elementData不为空说明刚此实例对象不是新初始化的,已经有元素了
//返回数据的实际大小
return minCapacity;
}
//通过之前的判断得到数据的大小minCapacity
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
//用数组中实际元素个数-数组长度
//如果结果>0,说明元素个数已经超过的数组的大小,不能继续添加元素,需要进行数组扩容
//如果结果<0,说明元素个数还没有超过的数组的大小,还可以继续添加元素
if (minCapacity - elementData.length > 0)
//扩容:minCapacity为实际元素个数+1
grow(minCapacity);
}
private void grow(int minCapacity) {
//得到数组的大小
int oldCapacity = elementData.length;
//通过位运算得到新数组的大小:旧数组大小+旧数组的大小的一半
int newCapacity = oldCapacity + (oldCapacity >> 1);
//判断新数组大小是否大于当前数组元素个数+1的大小
if (newCapacity - minCapacity < 0)
//如果newCapacity - minCapacity < 0说明新长度不能满足
//则将minCapacity当做新的数组长度
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//对数组进行扩容将elementData大小扩容为新的长度,并将老数组中大元素移动到新的数组中
elementData = Arrays.copyOf(elementData, newCapacity);
}
扩展:
Arrays的copyOf()方法传回的数组是新的数组对象,改变传回数组中的元素值,不会影响原来的数组。
copyOf()的第二个自变量指定要建立的新数组长度,如果新数组的长度超过原数组的长度,则保留数组默认值,例如:
import java.util.Arrays;
public class ArrayDemo {
public static void main(String[] args) {
int[] arr1 = {
1, 2, 3, 4, 5};
int[] arr2 = Arrays.copyOf(arr1, 5);
int[] arr3 = Arrays.copyOf(arr1, 10);
for(int i = 0; i < arr2.length; i++)
System.out.print(arr2[i] + " ");
System.out.println();
for(int i = 0; i < arr3.length; i++)
System.out.print(arr3[i] + " ");
}
}
结果:
1 2 3 4 5
1 2 3 4 5 0 0 0 0 0