ArrayList 每次扩容的情况下扩容为原来的1.5 倍。线程不安全,当多个线程同时访问同一个ArrayList 集合时,如果两个或两个以上的线程修改了 ArrayList 集合,则必须手动保证该集合的同步性。
Vector 是同步类,其线程安全,但是它的访问比较慢。Vector 每次扩容为其空间大小的 2 倍。
五、对扩容原理源码剖析及其思考
在add()方法中调用ensureCapacityInternal()方法,用来确保添加元素的时候,最小容量是 minCapacity。
源码剖析
private void ensureCapacityInternal(int minCapacity) {
// 判断元素数组是否为空数组
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 取最大值
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
在ensureCapacityInternal()方法里面调用ensureExplicitCapacity(int minCapacity)方法,用来判段集合在添加元素的时候是否需要对当前的数组进行扩容。
源码剖析
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
// 判断minCapacity与当前元素数组的长度的大小
// 如果minCapacity比当前元素数组的长度的大小大的时候需要扩容
if (minCapacity - elementData.length > 0)
// 扩容
grow(minCapacity);
}
在ensureExplicitCapacity() 方法里面调用grow(int minCapacity)方法,进行扩容。
源码剖析
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
// 原本的容量
int oldCapacity = elementData.length;
// 新的容量是原本容量的1.5倍
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);
}
/**
*hugeCapacity()方法,用于处理minCapacity超出MAX_ARRAY_SIZE的情况
*/
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
最后调用 Arrays.copyOf()方法,用来复制原数组,将 elementData 赋值为得到的新数组。
注意:
由于数组复制的代价比较大,因此建议在创建 ArrayList 对象的时候就指定大概的容量大小,从而减少扩容操作的次数。
六、ArrayList的优缺点
1. 优点
能够自动扩容,默认每次扩容为原来容量大小的1.5倍。
根据下标遍历元素,效率高。
根据下标访问元素,效率高。
2. 缺点
线程不安全。
根据下标查找元素的时候需要遍历整个元素数组,效率低。
插入和删除元素的时候需要移动元素,效率低。