public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
ArrayList继承了AbstractList抽象类,实现了List、RandomAccess、Serialzable接口,其实AbstaactList已经实现过List接口了,ArrayList又实现一次,可能是为了规范吧。
我们来看一下它的字段信息
//默认容量为10
private static final int DEFAULT_CAPACITY = 10
//空的数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//默认容量为空的数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//数组
transient Object[] elementData;
//数组大小
private int size;
它有一个入参为整型的构造方法,若传入值大于0,则创建传入值大小的数组,如果传入值为0,那么数组大小默认为0,否则将抛出IllegalArgumentException
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类型的变量,很简单,先将其转化为数组,如果长度不为0,且不为空,那么就把这个数组复制到elementData中,否则初始大小为0
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;
}
}
它还有一个无参构造方法,默认初始容量为0,DEFAULTCAPACITY_EMPTY_ELEMENTDATA 是一个空数组
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
在官方注释上标识数组初始容量为10是错的,这里下面会说
public boolean add(E e) {
//对数组大小进行检查,容量不足会进行扩容
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
在不指定ArrayList大小时,默认初始容量为0,然后在add操作时,会对数组容量进行检查,若数组已不足以存放这一个数据,那么会进行扩容,
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//如果elementData是一个空数组,那么会将它扩容为大小为10的数组
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
所以通常所说的初始容量为10,说的都是在执行第一次add操作之后,
get方法,因为java数组不允许越界,因此会先进行范围检查,然后返回数组元素。
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
set方法,同样会检查是否越界,然后将数组元素
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
remove方法,将指定索引的元素移除,国际惯例检查越界,将索引处值赋给中间变量oldValue用来返回,然后会将索引后的元素移动一个位置,
然是这样效率太低,因此,直接将后面的数组直接复制过去
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
这也是为什么ArrayList增删的速度较慢的原因,但是其查找速度快,因为毕竟底层是数组嘛!