ArrayList类中的一些成员变量:
private static final int DEFAULT_CAPACITY = 10;//默认初始容量为10
transient Object[] elementData;// 保存ArrayList数据的数组
private int size;//ArrayList 所包含的元素个数
private static final Object[] EMPTY_ELEMENTDATA = {};//空数组(用于空实例)。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//用于默认大小空实例的共享空数组实例。
//我们把它从EMPTY_ELEMENTDATA数组中区分出来,以知道在添加第一个元素时容量需要增加多。
ArrayList有三个构造函数:下面我们依次来分析
- 1.指定初始容量的构造函数
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);
}
}
由代码可知,该构造函数会创建一个大小为initialCapacity的数组
- 2.无参构造
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
由代码可知,该构造函数会创建一个空数组
- 3.构造包含指定collection元素的列表,这些元素利用该集合的迭代器按顺序返回
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
System.arraycopy():将指定源数组中的数组从指定位置复制到目标数组的指定位置。
@ src – 这是源数组 @ srcPos – 这是源数组中的起始位置 @dest – 这是目标数组 @ destPos – 这是目标数据中的起始位置 @ length – 这是一个要复制的数组元素的数目
举例:
int arr1[] = {0,1,2,3,4,5};
int arr2[] = {0,10,20,30,40,50};
System.arraycopy(arr1,0,arr2,1,2);
结果:arr2 = [0,0,1,30,40,50];
Arrays.copyOf() :以正确的顺序返回一个包含此列表中所有元素的数组(从第一个到最后一个元素); 返回的数组的运行时类型是指定数组的运行时类型。这个方法在这里的主要作用就是给数组扩容
举例:
public static void main(String[] args) {
int[] a = new int[3];
a[0] = 0;
a[1] = 1;
a[2] = 2;
int[] b = Arrays.copyOf(a, 10);
System.out.println(b.length);
for (int i = 0; i < b.length; i++) {
System.out.print(b[i] + " ");
}
}
结果:
10
0 1 2 0 0 0 0 0 0 0
再来分析add()方法
分两种情况讨论:
- 1.无参构造第一次add
Arraylist有两个add()重载方法,这里只分析public boolean add(E e)这种情况
:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
在add(E e)
方法中调用了ensureCapacityInternal(size+1)
方法,这里传入的参数size+1
就是插入当前元素数组所需的最小容量,由于是无参构造,此时传入的参数size+1
即minCapacity
为1,ensureCapacityInternal(size+1)
调用了ensureExplicitCapacity(calculateCapacity(elementData, minCapacity))
方法,该方法中的calculateCapacity(Object[] elementData, int minCapacity)
方法作用是计算数组容量,此时elementData
为空所以返回默认容量10,最后ensureExplicitCapacity()
中判断当前数组为0小于所需数组容量10,所以进行扩容,也就是grow(minCapacity)
方法, 下面具体分析这个函数:
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
所以此时的elementData
的长度为0,所以oldCapacity
和newCapacity
都为0if (newCapacity - minCapacity < 0)
条件满足newCapacity
为10,最后elementData = Arrays.copyOf(elementData, newCapacity);
通过复制组数进行扩容,Arrays.copyOf前面已经分析过。
- 2.无参构造非第一次add
在add(E e)
方法中调用了ensureCapacityInternal(size+1)
方法,假设是第二次add此时传入的参数size+1
即minCapacity
为2,ensureCapacityInternal(size+1)
调用了ensureExplicitCapacity(calculateCapacity(elementData, minCapacity))
方法,此时elementData
为1所以返回minCapacity2,最后ensureExplicitCapacity()
中判断,当前数组在第一次add时已经扩容为10大于所需数组容量2,所以不进行扩容。只有当第11次add时才会再次扩容,我们分析当前情况下的grow()函数
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int `newCapacity` = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
此时传入的参数minCapacity为11,oldCapacity = elementData.length;
为10,newCapacity
扩容为原来的1.5倍.最后通过Arrays.copyOf()方法完成扩容。
`
结论
Arraylist实现无参构造方法时数组为空数组,第一次add()时会将数组扩容为10,直到添加的数组个数大于10时会再次扩容,扩容大小为原来数组的1.5倍,依次类推。
Arraylist实现带初始容量的构造方法时数组大小为用户设置的初始容量,若设置的初始容量小于10,当添加的数组超过用户设置的初始容量会自动扩容为10,若设置的初始容量大于10,则当添加的数组超过用户设置的初始容量会自动扩容为原来的1.5倍。