ArrayList概述
ArrayList是一个可调整容量大小的数组,其实现了List接口,可以存放任意元素包括null,其内部实现是数组,get、set、Iterator操作是固定时间内运行,效率较高,但是add、remove操作效率稍低。不是线程安全的类,如果有多个线程访问该类的实例,并且至少有一个线程在修改列表,则必须在外部进行同步
成员变量
// 初始化时如果没有指定容量大小,则默认容量为10
private static final int DEFAULT_CAPACITY = 10;
// 当没有元素时赋值为此空对象
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 以数组形式维护其内部成员,以transient关键字声明,说明其成员不参与序列化
transient Object[] elementData;
private int size;//ArrayList 内部当前维护的元素个数
构造函数
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;//初始化为空对象
}
// 用另外一个集合初始化
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;
}
}
// 以给定容量大小初始化
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);
}
}
成员方法
添加新元素
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 以当前元素个数+1,与capacity比较,如果容量不够,则扩容
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
// 如果列表中没有元素时,取当前容量与minCapacity中的最大值
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 如果容量不够用了,开始扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;// 当前元素个数
int newCapacity = oldCapacity + (oldCapacity >> 1);// 新容量为旧容量的1.5倍
if (newCapacity - minCapacity < 0)// 如果新容量小于比较值,取比较值为新的容量大小
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)// 如果超过了最大支持容量数
newCapacity = hugeCapacity(minCapacity);// 大容量数组检验
// 当前元素复制到新扩容的空间中,此处涉及到内存数据复制
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // 数据溢出,抛异常, 否则取整型数的最大值为新容量
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
给指定位置添加新元素
public void add(int index, E element) {
if (index > size || index < 0)// 边界检查,越界时抛出异常
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
ensureCapacityInternal(size + 1); // 与上面add方法基本一致
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;// 将新元素插入到指定索引位置
size++;
}
ArrayList 在添加新元素的过程中,如果当闪容量不中以存储下元素的数量,则需要进行扩容操作,int newCapacity = oldCapacity + (oldCapacity >> 1); 这一句代码表明:一般情况下扩容时都是以旧容量的1.5倍进行扩容
移除元素
public E remove(int index) {
if (index >= size)// 越界,抛出异常
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
modCount++;
E oldValue = (E) elementData[index];// 指定位置的元素
int numMoved = size - index - 1;// 计算需要做内存移动的元素数量
if (numMoved > 0)// 如果需要移动,将index后面的元素向前移动到时合适位置
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // 将最后一个元素置空,之后可能会触发GC
return oldValue;// 返回要删除的元素
}
set、get
set方法直接将指定位置替换为新元素,最后将老元素返回
get方法直接将指定位置的元素返回
public E set(int index, E element) {
if (index >= size)// 越界抛异常
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
E oldValue = (E) elementData[index];
elementData[index] = element;
return oldValue;
}
public E get(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
return (E) elementData[index];
}
总结
-
以数组维护内部数据
-
容量大小自动调节,容量不够时1.5倍旧容量大小扩容
-
添加删除操作效率较低,遍历西西查找效率较高
-
不是线程安全的实现
-
内容可重复,可以为null