private static final long serialVersionUID = 8683452581122892189L;
private static final int DEFAULT_CAPACITY = 10; //初始容量
private static final Object[] EMPTY_ELEMENTDATA = new Object[0]; //空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
transient Object[] elementData; //存储数组,根据需要进行初始化
private int size; //存储元素的数量
private static final int MAX_ARRAY_SIZE = 2147483639; //最大容量,此时接近于2的32次方,可再次扩容到2的32次方减一
ArrayList的类字段中定义了序列化ID、初始容量、最大容量、元素存储数组、元素数量等信息。从类字段中可以分析出,ArrayList的底层使用的是Object数组来存储元素,至于他的数组长度的可变性则是在该类中自己实现的逻辑。初始容量为10,最大容量为接近于2的32次方,当超过这个后,最大容量扩大到2的32次方。
1、无参构造函数
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
无参构造函数只是将存储元素的数组初始化为默认的空元素数组,此时的数组的容量为零。此时的数组容量并不是默认的数组容量10,而是在第一个元素add时才扩容为10的。
2、有参构造函数
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else {
if (initialCapacity != 0) {
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
}
this.elementData = EMPTY_ELEMENTDATA;
}
}
拥有一个参数,就是初始化容量,为int值。当该值大于零时,数组初始化为该容量大小的数组,当该值小于零是,抛出非法参数异常,当该值为零时,初始化为空数组。
public ArrayList(Collection<? extends E> c) {
Object[] a = c.toArray();
if ((this.size = a.length) != 0) {
if (c.getClass() == ArrayList.class) {
this.elementData = a;
} else {
this.elementData = Arrays.copyOf(a, this.size, Object[].class);
}
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
构造一个指定集合的列表,Collection作为参数传入。首先将该Collection存储的元素转化为Object数组,如果该数组的长度为零,则将ArrayList初始化为空数组。如果该数组长度不为零,分两种情况,第一种情况是传入的集合就是ArrayList类型的,则直降将elementData数组初始化为转化后的数组。如果不是ArrayList类型的,则将其拷贝为一个新数组用来初始化elementData。
Arrays.copyOf方法是浅拷贝,存储的对象是一样的,只是生成了新的引用,指向的还是原来的对象(打印拷贝前后对象的地址进行对比,发现地址一样)。
public boolean add(E e) {
++this.modCount; //修改次数加一
this.add(e, this.elementData, this.size); //调用的是一个重载的方法
return true;
}
//上面的add调用的是该方法
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length) { //如果长度已经达到最大,则扩充长度
elementData = this.grow();
}
elementData[s] = e; //否则直接将元素添加到数组中,并将size加一
this.size = s + 1;
}
//将元素添加到指定位置
public void add(int index, E element) {
this.rangeCheckForAdd(index); //index范围检查,超出则抛出异常
++this.modCount; //修改加一
int s;
Object[] elementData;
if ((s = this.size) == (elementData = this.elementData).length) { //达到数组容量则扩容
elementData = this.grow();
}
System.arraycopy(elementData, index, elementData, index + 1, s - index); //元素后移
elementData[index] = element; //添加元素
this.size = s + 1; //size加一
}
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
JVM的数组拷贝方法,将原数组的srcPos位置开始的length长元素,拷贝到dest数组的destPos开始的位置。
//将指定Collection添加到现有的ArrayList中元素的后面
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
++this.modCount;
int numNew = a.length;
if (numNew == 0) {
return false;
} else {
Object[] elementData;
int s;
if (numNew > (elementData = this.elementData).length - (s = this.size)) {
elementData = this.grow(s + numNew); //容量不够则扩容
}
System.arraycopy(a, 0, elementData, s, numNew); //拷贝到现有元素的后面
this.size = s + numNew; //size增加
return true;
}
}
//将指定Collection添加到现有的ArrayList的指定位置的后面,原有的则顺延到添加元素的后面
public boolean addAll(int index, Collection<? extends E> c) {
this.rangeCheckForAdd(index);
Object[] a = c.toArray();
++this.modCount;
int numNew = a.length;
if (numNew == 0) {
return false;
} else {
Object[] elementData;
int s;
if (numNew > (elementData = this.elementData).length - (s = this.size)) {
elementData = this.grow(s + numNew); //如果容量存不下,则扩容
}
int numMoved = s - index;
if (numMoved > 0) { //拷贝原数组空出中间位置
System.arraycopy(elementData, index, elementData, index + numNew, numMoved);
}
//拷贝Collection到ArrayList中
System.arraycopy(a, 0, elementData, index, numNew);
this.size = s + numNew; //size增加
return true;
}
}
//通过传入的容量来扩容,扩容通过数组拷贝实现,实际的容量由newCapacity函数决定
private Object[] grow(int minCapacity) {
return this.elementData = Arrays.copyOf(this.elementData, this.newCapacity(minCapacity));
}
//最开始的扩容函数,调用重载函数,并传入当前size加一作为参数
private Object[] grow() {
return this.grow(this.size + 1);
}
//实际的扩容策略
private int newCapacity(int minCapacity) {
int oldCapacity = this.elementData.length; //获取老数组的长度
int newCapacity = oldCapacity + (oldCapacity >> 1); //扩容1.5倍
if (newCapacity - minCapacity <= 0) { //安全策略,以为扩容后可能导致溢出
if (this.elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(10, minCapacity); //如果是数组,则设置默认数组容量,对应于第一次add
} else if (minCapacity < 0) {
throw new OutOfMemoryError(); //当达到数组最大容量,int最大值溢出后,抛出异常
} else {
return minCapacity; //当老数组超过三分之二时,newCapacity会溢出,
//此时就是每次添加数组加一。所以ArrayList的
}
} else { //如果没有溢出,但是又不够,则最大容量扩大。否则返回新容量
return newCapacity - 2147483639 <= 0 ? newCapacity : hugeCapacity(minCapacity);
}
}
//扩大最大容量
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) { //超出抛异常
throw new OutOfMemoryError();
} else { //扩容到最大的2的32次方减1
return minCapacity > 2147483639 ? 2147483647 : 2147483639;
}
}
扩容总结:
1)当容量的1.5倍没有溢出,按1.5倍原容量扩容
2)容量的1.5倍溢出,分几种情况
- 第一次添加:设置默认初始容量10
- 老数组已经达到最大容量:溢出抛异常
- 老数组的1.5倍溢出:老数组加一
3)容量的1.5倍超过max容量,但是未溢出int取值范围,则扩容至int的最大值
//删除指定索引处的元素
public E remove(int index) {
Objects.checkIndex(index, this.size); //检验索引正确性
Object[] es = this.elementData;
E oldValue = es[index];
this.fastRemove(es, index); //调用fastRemove进行删除
return oldValue; //返回删除元素
}
private void fastRemove(Object[] es, int i) {
++this.modCount;
int newSize;
if ((newSize = this.size - 1) > i) {
System.arraycopy(es, i + 1, es, i, newSize - i); //通过拷贝来删除
}
es[this.size = newSize] = null; //最后的元素设置为null
}
//删除指定元素,返回值为boolean
public boolean remove(Object o) {
Object[] es = this.elementData;
int size = this.size;
int i = 0;
if (o == null) { //非null或非null,在数组中找到第一个然后调用fastRemove进行删除,如果没有,则返回false
while(true) {
if (i >= size) {
return false;
}
if (es[i] == null) {
break;
}
++i;
}
} else {
while(true) {
if (i >= size) {
return false;
}
if (o.equals(es[i])) {
break;
}
++i;
}
}
this.fastRemove(es, i);
return true;
}
//删除指定索引范围内的元素
protected void removeRange(int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IndexOutOfBoundsException(outOfBoundsMsg(fromIndex, toIndex));
} else {
++this.modCount;
this.shiftTailOverGap(this.elementData, fromIndex, toIndex);
}
}
private void shiftTailOverGap(Object[] es, int lo, int hi) {
System.arraycopy(es, hi, es, lo, this.size - hi); //拷贝删除范围后的到删除初始位置
int to = this.size;
for(int i = this.size -= hi - lo; i < to; ++i) { //删掉多余的元素
es[i] = null;
}
}
//删除或保留指定集合中包含的所有元素
public boolean removeAll(Collection<?> c) { //删除指定指定集合包含的元素
return this.batchRemove(c, false, 0, this.size);
}
public boolean retainAll(Collection<?> c) { //保留指定集合包含的元素
return this.batchRemove(c, true, 0, this.size);
}
boolean batchRemove(Collection<?> c, boolean complement, int from, int end) { //实际调用的方法
Objects.requireNonNull(c);
Object[] es = this.elementData;
for(int r = from; r != end; ++r) {
if (c.contains(es[r]) != complement) { //如果存在
int w = r++;
try {
for(; r < end; ++r) {
Object e;
if (c.contains(e = es[r]) == complement) { //循环前移
es[w++] = e;
}
}
} catch (Throwable var12) {
System.arraycopy(es, r, es, w, end - r);
w += end - r;
throw var12;
} finally {
this.modCount += end - w;
this.shiftTailOverGap(es, w, end);
}
return true;
}
}
return false;
}
public void clear() {
++this.modCount;
Object[] es = this.elementData;
int to = this.size;
for(int i = this.size = 0; i < to; ++i) { //遍历整个数组设置为null,并把size设置为0
es[i] = null;
}
}
//获取指定索引处的元素,由于是数组存储,所以复杂度是O(1)
public E get(int index) {
Objects.checkIndex(index, this.size);
return this.elementData(index);
}
//设置指定索引处的值,并返回之前的值
public E set(int index, E element) {
Objects.checkIndex(index, this.size);
E oldValue = this.elementData(index);
this.elementData[index] = element;
return oldValue;
}
//整理ArrayList,将其容量设置为当前元素size大小
public void trimToSize() {
++this.modCount;
if (this.size < this.elementData.length) {
this.elementData = this.size == 0 ? EMPTY_ELEMENTDATA : Arrays.copyOf(this.elementData, this.size); //copyOf返回新数组对象
}
}
//返回当前ArrayList中元素的个数
public int size() {
return this.size;
}
//判断ArrayList中是否有元素
public boolean isEmpty() {
return this.size == 0;
}
//判断是否包含指定元素,调用indexOf判断
public boolean contains(Object o) {
return this.indexOf(o) >= 0;
}
//调用indexOfRange判断
public int indexOf(Object o) {
return this.indexOfRange(o, 0, this.size);
}
//最终判断逻辑,判断是否包含指定元素
int indexOfRange(Object o, int start, int end) {
Object[] es = this.elementData;
int i;
if (o == null) { //因为可添加null,所以判断null
for(i = start; i < end; ++i) {
if (es[i] == null) {
return i;
}
}
} else {
for(i = start; i < end; ++i) {
if (o.equals(es[i])) {
return i;
}
}
}
return -1; //没有则返回-1
}
//从后往前判断是否包含指定元素
public int lastIndexOf(Object o) {
return this.lastIndexOfRange(o, 0, this.size);
}
int lastIndexOfRange(Object o, int start, int end) {
Object[] es = this.elementData;
int i;
if (o == null) {
for(i = end - 1; i >= start; --i) {
if (es[i] == null) {
return i;
}
}
} else {
for(i = end - 1; i >= start; --i) {
if (o.equals(es[i])) {
return i;
}
}
}
return -1; //没有返回-1
}
//转化为数组,分两种,这一种是不传入参数,转化为Object数组
public Object[] toArray() {
return Arrays.copyOf(this.elementData, this.size);
}
//第二种是传入具体的数组类型,转化为具体类型的数组。如果类型不匹配,编译器会报错。
//传入的参数可以为new T[0],返回会重新生成一个新的T[]类型的数组
public <T> T[] toArray(T[] a) {
if (a.length < this.size) {
return Arrays.copyOf(this.elementData, this.size, a.getClass());
} else {
System.arraycopy(this.elementData, 0, a, 0, this.size);
if (a.length > this.size) {
a[this.size] = null;
}
return a;
}
}
//排序,实际调用的是Arrays中的sort
public void sort(Comparator<? super E> c) {
int expectedModCount = this.modCount;
Arrays.sort(this.elementData, 0, this.size, c);
if (this.modCount != expectedModCount) {
throw new ConcurrentModificationException();
} else {
++this.modCount;
}
}
//返回子序列,返回的是一个ArrayList中内部类的实例
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, this.size);
return new ArrayList.SubList(this, fromIndex, toIndex);
}
1、ArrayList底层使用的是Object数组。
2、初始容量为10,可传入参数设置初始化容量。无参构造时,初始化容量为0,第一个add时容量扩为初始容量10。
3、基础扩容策略为原数组长度的1.5倍。超过最大容量但是还未溢出,则扩大最大容量。超过三分之二,则每次加一。溢出int最大值则抛出异常。
4、增加和删除使用的都是arrayCopy方法。实现RandomAccess,可支持快速访问,推荐遍历使用for。增删复杂度O(n),查询和修改复杂度O(1)。