public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
/**
实现使用的标记接口表示*它们支持快速(通常为恒定时间)随机访问。该接口的主要目的是允许通用算法更改其行为,以便在应用于随机访问或顺序访问列表时提供良好的性能
*/
public interface RandomAccess {
}
不得不说,阅读源码前去参考一遍注释会让自己能有一个明确的思路,甚至明白一些自己写出的bug原因。
ArrayList 被解释为List接口的可调整大小的数组实现。大致来说其中所有的操作都是线性运行的,于LinkList实现的常量相比,常量因子较低。每个 ArrayList实例都有一个<i>容量</ i>。容量是*用于在列表中存储元素的数组的大小。它总是至少等于列表大小。随着元素被添加到ArrayList中,其容量会自动增长。除了添加元素具有固定的摊销时间成本外,没有指定增长策略的细节。
我理解上述问题,即为ArrayList 增长策略只是单个根据元素插入个数确定要增加的容量,稍等测试,可以调用ensureCapacity()方法进行大量数据插入前的扩容。但是方法未实现同步,多个线程同时访问如果修改需同步至外部。否则会被覆盖。
//默认容量为10
private static final int DEFAULT_CAPACITY = 10;
// 缩小当前实例的大小 等于 当前实例的实际大小 实例的容量调整为列表的当前大小。
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
Arraylist 扩展容量的方法在add()/addAll()发给发时候回进行调用,首先确认(当前容量+1)是否能够容纳下原数组与新增的实体数量,不能就在原容量基础上扩大两倍,仍不够就使用最大容量。
// add() 默认追加到当前list 最后的位置
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
// add() 都需要先确认当前数组的容量 然后进行插入 addAll进行数组拷贝进行插入 size为当前数组list 的容量属性 初始化已经赋值 且特殊操作进行更新
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
// elementData 为当前数组list 中的所有元素
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 int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
其上代码 可以看到一个扩容的链路调用。
前几天,需要使用到List<String>与数组Array 之间的转换,这里其实使用到的还是java.util.Arrays 的拷贝方法
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
快速失败 比较 modcount 在 Abstractlist 中有详细代码