ArrayList简介
ArrayList是Java中常用的Collection集合实现类,底层由Object数组实现。与array数组相比,它具有动态扩展的能力(动态扩容)。
ArrayList继承关系
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
ArrayList类继承AbstractList(抽象类),实现了List接口,Cloneable接口(克隆),RandomAccess接口(随机访问),Serializable接口(序列化)。
List接口继承了Collection接口,Collection接口继承了Iterable接口,故ArrayList是Collection接口的实现子类,同样也是Iterable接口(迭代器)的实现子类,同时具有迭代器的方法。
ArrayList list = new ArrayList(3);
list.add(1);
list.add(2);
list.add(3);
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
System.out.println(next);
}
ArrayList源码分析
重要的成员变量如下:
//默认初始容量
private static final int DEFAULT_CAPACITY = 10;
//空数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//与空数组elementData区分开,调用ArrayList无参构造器时候,赋值给elementData
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//真正存放element的数组
transient Object[] elementData; // non-private to simplify nested class access
//数组的真实长度
private int size;
1.无参构造
/**
* 当调用ArrayList无参构造器时,底层elementData数组被初始化为一个空数组
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
2.有参构造
/**
* 当入参initialCapacity大于0时,底层elementData数组会被初始化为指定大小的Object数组
* 当入参initialCapacity等于0时,底层elementData数组会被赋值为一个空数组(EMPTY_ELEMENTDATA)
* 当入参initialCapacity小于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);
}
}
3.add(E e)方法
public boolean add(E e) {
ensureCapacityInternal(size + 1);
//以上代码执行完成后,将对象添加到数组中
//size增加1
elementData[size++] = e;
//返回添加成功
return true;
}
// 首先ArrayList执行add方法时,
// 先获取底层存储对象的数组真实长度size
// 添加对象时,意味着minCapacity(最小容量)应该等于原来的size + 1
private void ensureCapacityInternal(int minCapacity) {
//如果底层数组elementData为空数组
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//那么minCapactity就等于(DEFAULT_CAPACITY(也就是10)与minCapacity 之间取最大的那个值)
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
//数组更改次数(每次增加一个对象,更改次数就加1)
modCount++;
// 当调用的是无参构造器声明ArrayList并且第一次添加对象时,minCapacity=10,elementData.length=0
// 当ArrayList底层数组已经被填满时,再添加对象时,minCapacity(最小所需容量)就会大于底层数组的长度,进而触发扩容
if (minCapacity - elementData.length > 0)
// 上面条件成立,执行grow方法
grow(minCapacity);
}
//真正的扩容方法
private void grow(int minCapacity) {
// 获取底层数组elementData的长度
int oldCapacity = elementData.length;
// newCapacity = oldCapacity + oldCapacity / 2
int newCapacity = oldCapacity + (oldCapacity >> 1);
// newCapacity 小于 minCapacity,将minCapacity的值赋给newCapacity
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 执行扩容,并将原数组数据拷贝进来
elementData = Arrays.copyOf(elementData, newCapacity);
}
add方法总结:
1.调用无参构造器创建ArrayList
①首次add对象时,ArrayList底层数组的容量会先被初始化为10。
②当ArrayList底层数组被填满后,再次add对象时,底层数组的容量会扩容至原来的1.5倍,并将原数组数据拷贝进来。
3.调用有参构造器创建ArrayList
①首先将底层数组初始化为指定入参的大小。
②当ArrayList底层数组被填满后,再次add对象时,底层数组的容量会扩容至原来的1.5倍,并将原数组数据拷贝进来。
ArrayList的特点
1.由于ArrayList底层是Object数组,因此查询速度较快。
2.add(E e)方法默认是从底层数组的末尾进行添加,所以时间复杂度为O(1)
3.add(int index, E element)方法,指定位置添加对象,其时间复杂度为O(n),因为数组要在index增加成员,势必会造成数组索引的变化(涉及到移动其他成员)。
4.remove(int index)方法,也会导致数组索引的变化。所以ArrayList 增删相对较慢。
5.ArrayList中的方法是非线程安全的,因此多线程环境下操作集合,不推荐使用ArrayList。