一、ArrayList简介
- ArrayList是用一个数组实现的集合,支持随机访问,元素有序且可以重复。
- ArrayList是一种变长的集合类,基于定长数组实现。
- ArrayList允许空值和重复元素,当在其添加的元素数量大于其底层数组容量是,其会通过扩容机制重新生成一个更大的数据。
- ArrayList底层基于数组实现,所以可以保证在0(1)复杂度下完成随机查找操作。
- ArrayList并非线程安全类,在并发环境下,多个线程同时操作ArrayList,会引发不可预知的异常或错误。

RandomAccess接口:标记接口,一边用于list的实现,表示支持快速随机访问
Cloneable:同标记接口,表示可以被克隆
Serializable:标记接口,表示可以被序列化
List:List类集合的上层接口,定义了实现该接口的类都必须要实现的一组方法
二、方法解析
1.无参构造
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};这里其实只是相当于创建了一个空数组,并不是认为的10。
2.有参构造
private static final Object[] EMPTY_ELEMENTDATA = {};
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);
}
}这时候是根据传进来的数组长度进行创建,如果为0的话,则会是一个空数据,小于0则抛异常
3.重载:ArrayList(Collection<?extends E> c)
public ArrayList(Collection<? extends E> c) {
Object[] a = c.toArray();
if ((size = a.length) != 0) {
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {
// replace with empty array.
elementData = EMPTY_ELEMENTDATA;
}
}将已有的集合赋值到ArraryList集合中
结合上面几点产生疑惑,无参构造和0长度构造的区别?
结论:
当一个无参构造的ArrayList添加第一个元素时,会给数组扩容到10并在剩余空间中都存放null
0长度构造的ArrayList则是添加该元素就结束了

原理:
//calculateCapacity
//每次元素变动,比如add,会调用该函数判断容量情况
private static int calculateCapacity(Object[] elementData, int minCapacity)
{
//定义default empty数组的意义就在这里!用于扩容时判断当初采用的是哪种构造函数
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//如果是无参的构造函数,用的就是该default empty
//那么第一次add时候,容量取default和min中较大者
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
//如果是另外两个构造函数,比如指定容量为5,或者初始参数collection为5
//那就直接返回5,一定程度上,节约了内存空间
return minCapacity;
}4.添加元素
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}在添加元素之前会计算是否需要扩容,根据当前所需要的最小容量来进行计算,如果需要的最小容量减去当前数组长度大于0,也就是不能满足的时候,就会进行扩容。
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);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;扩容的时候会将之前的容量转化成2进制右移一位,就像对于除以2,然后再加上之前的旧容量,也就相当于扩大了1.5倍。之后再判断是否满足容量以及是否超过最大长度,也就是int的最大值-8,之后就是创建出这个数据并将原来的值拷贝进其中并返回即可。
5,删除元素
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;
}首先先是检查是否有索引越界,然后拿到需要删除的元素,接着去判断是否为最后一个元素,因为如果是最后一个元素的话,直接将其置为null即可,不需要将index+1的元素移到index的位置上;如果不是最后一个元素的话,会通过arraycopy对数组进行自身的拷贝

6.修改元素
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}简单的获取并覆盖而已,如果index是负数则会抛出异常
7.查找元素
public E get(int index) {
rangeCheck(index);
return elementData(index);
}8.迭代器遍历
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}前面在新增元素add() 和 删除元素 remove() 时,我们可以看到 modCount++,修改的set是没有的
也就是说不能再迭代器进行元素迭代时进行增加和删除操作,否则会抛出异常。
另外再进行next方法调用时,因为会进行checkForComodification调用,如果同时进行增加和删除则会抛异常,解决方法是不调用 ArrayList.remove() 方法,而是调用迭代器的remove方法
最后一点,我们所熟知的增强for其实就是迭代器便利的,这点我们可以通过反编译看到效果。
ArrayList list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
String str;
for (Iterator iterator1 = list.iterator(); iterator1.hasNext();
System.out.print((new StringBuilder(String.valueOf(str))).append("
").toString()))
str = (String)iterator1.next();以上就是ArrayList类中重要的方法已经原理