一、toArray方法
1.无参方法
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
ArrayList底层用数组来存储数据,这里的elementData是数组名,size为数组里面的元素个数。
无参方法是调用数组工具类将所有数据全部拷贝一份。调用方法返回的是一个新的数组,因此,调用者可以自由地修改返回的数组。
2.有参方法
public <T> T[] toArray(T[] a) {
// 1.当传入数组的长度<ArrayList底层实际的数据长度
if (a.length < size)
// 仅使用传入数组的数据类型,底层调用数组工具类的复制方法
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
// 2.当传入数组的长度>=ArrayList底层实际的数据长度,使用传入的数组
// 使用系统提供的arraycopy数组拷贝方法,将elementData的数据,全部拷贝到a
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
// 3.如果传入数组的长度>数据长度,在最后一位元素后的位置做一个标记
a[size] = null;
return a;
}
二、构造方法及扩容代码
1.构造方法
public class ArrayList {
//ArrayList底层用来存储数据的数组
transient Object[] elementData;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//记录修改次数
protected transient int modCount = 0;
private int size;
//规定默认容量为10
private static final int DEFAULT_CAPACITY = 10;
public ArrayList() {
//构造一个空列表,此时并没有进行数据的初始化工作
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//直到开始往集合中添加数据,即调用add方法时,进行初始化
public boolean add(E e) {
modCount++;
//调用多参add方法
add(e, elementData, size);
return true;
}
}
当一个新创建的集合调用add方法,其传入多参add方法中的size为0:
private void add(E e, Object[] elementData, int s) {
//s即为size 此时size为0,数组的长度也为0,进入grow方法
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
private Object[] grow() {
//grow(1)
return grow(size + 1);
}
private Object[] grow(int minCapacity) {
//oldCapacity旧容量为0
int oldCapacity = elementData.length;
//此时,oldCapacity=0且elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 进入else
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
} else {
//默认容量为10,传入的最小容量为1,取最大值10,创建一个长度为10的数组返回
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
2.扩容方法
假设一个集合,不停地向其中添加数据直至size为10,此时要进行扩容。简单来说是按照1.5倍进行扩容:
private void add(E e, Object[] elementData, int s) {
//当size=10时,底层数组的长度为初始默认容量10,进入grow方法扩容
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
private Object[] grow() {
//grow(11)
return grow(size + 1);
}
private Object[] grow(int minCapacity) {
//此时,旧容量为10
int oldCapacity = elementData.length;
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//旧容量10>0,直接进入
//对于新容量的确定调用了ArraysSupport的newLength方法,已复制在下方
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
//得到新容量15,将原有数据复制进新数组即可
return elementData = Arrays.copyOf(elementData, newCapacity);
} else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
//ArraysSupport的newLength方法:
public static final int SOFT_MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;
public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
//传入的参数为:旧容量10,minGrowth=minCapacity - oldCapacity=11-10=1,prefGrowth=10>>1=5
int prefLength = oldLength + Math.max(minGrowth, prefGrowth);
//计算prefLength为15
if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {
//一般来说,计算出的值都>0且<=int最大值-8,所以直接返回15
return prefLength;
} else {
// put code cold in a separate method
return hugeLength(oldLength, minGrowth);
}
}