public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
可以看出:
1.ArrayList 继承了AbstractList抽象类并且实现了List接口,所以提供了数组有关的添加、删除、修改、遍历等功能
2.ArrayList 实现了RandmoAccess接口,即提供了随机访问功能。也就是说,可以通过索引来快速获取元素对象,时间复杂度O(1),这里是与LinkedList一个显著区别。
3.ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。
总的来说:
ArrayList是List接口的可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。
每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向ArrayList中不断添加元素,其容量也自动增长。自动增长会带来数据向新数组的重新拷贝,因此,如果可预知数据量的多少,可在构造ArrayList时指定其容量。在添加大量元素前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这可以减少递增式再分配的数量。
注意,此实现不是同步的。如果多个线程同时访问一个ArrayList实例,而其中至少一个线程从结构上修改了列表,那么它必须保持外部同步。
底层其实是数组的实现,保存所有元素,基本操作也都是基于数组的。
private static final int DEFAULT_CAPACITY = 10;//默认初始容量大小
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//说明其底层实现是个数组
transient Object[] elementData;
ArrayList类中有3种构造函数,一个指定容量大小的构造器,一个默认容量为10的构造器以及构造一个包含指定collection的元素的列表,这些元素按照该collection的迭代器返回它们的顺序排列的。
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {//等于0,直接返回空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(Collection extends E> c) {
elementData = c.toArray();//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;
}
}
在添加元素之前,有个操作必须进行,那就是检查ArrayList有没有满,因为底层是数组就存在越界的风险。所以我们就要确保,add(),addAll()这些方法不越界。使用ensureCapacity();ensureCapcityInternal();ensureExplicitCapacity()方法。
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;//数组有改变,modCount就+1
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);//使容量扩大,但不是无限制的扩大,有上线的
}
//这就是ArrayList的最大容量,是VMs允许的最大容量,超出这个容量会报出OutOfMemoryError信息
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
//将指定元素添加到尾部
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!增加数组容量
elementData[size++] = e;
return true;
}
//任何后续的元素移动到右边
//在指定位置添加元素
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // 保证数组大小
System.arraycopy(elementData, index, elementData, index + 1,
size - index); //拷贝元素从源elementData的index开始往后的所有元素,到目的elementData的index+1开始的位置
elementData[index] = element;
size++;//容量加1
}
//添加一个Collection集合
public boolean addAll(Collection extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount再原有大小上增加容量
System.arraycopy(a, 0, elementData, size, numNew);//把a数组从0开始的numNew个元素,拷贝到elementData的size开始,newNew个
size += numNew;
return numNew != 0;
}
//根据索引取元素
public E get(int index) {
rangeCheck(index);//检查索引是否越界
return elementData(index);
}
//根据索引修改元素,返回旧元素
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue; //返回的是先前在index位置上的旧元素
}
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; // 清空,让GC回收
return oldValue;
}
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
/* 这个方法很有意思,首先是私有的,只给本身的类使用。说是fastRemove是因为不用边界检查,
*也不用返回旧元素,更加快速,谁知道呢 ,其实等同于remove(int index)方法*/
private void fastRemove(int index) {
modCount++;
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
}