当ArrayList 使用无参构造时,默认大小为10 ,也就是说在第一次add 的时候,分配为10 的容量,后续的每次扩容都会调用Array. copyOf 方法,创建新数组再复制。可以想象, 假如需要将1000个元素放置在ArrayList 中,采用默认构造方法,则需要被动扩容13 次才可以完成存储。反之,如果在初始化时便指定了容量new ArrayList(l 000), 那么在初始化ArrayLi st 对象的时候就直接分配1000 个存储空间,从而避免被动扩容和数组复制的额外开销。最后,进一步设想,如果这个值达到更大量级, 却没有注意初始的容量分配问题, 那么无形中造成的性能损耗是非常大的, 甚至导致OOM 的风险。所以,一定不要使用无参的方式构建ArrayList,构建时要设置合理的容量。
主要成员变量有两个:Object[] elementData和int size。一个用于存放数组元素,一个代表现有的元素个数。elementData的长度,就是当前的容量,默认为10,已oldCapacity + (oldCapacity >> 1)的方式进行扩容。最大容量为Integer.MAX_VALUE
elementData就是元素存放的数组。在构建的时候,如果提供了Capacity,直接就对elementData初始化了,如果是无参构造,则为定义好的长度为0的数组。无参构造在第一次添加元素时,会构建一个长度为10的对象数组。
/**
*默认容量
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 用于空实例的共享空数组实例。
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 用于默认大小的空实例的空数组实例,分开是为了第一次添加元素时扩容
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 存储ArrayList元素的数组缓冲区,
* 第一次添加元素时会被扩充到10(DEFAULT_CAPACITY)
* 就是Arraylist真正存储元素的地方。
* 注意这里是Object。ArrayList中的元素都被强转为Object存储在这地方了
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* 表示元素的个数
*/
private int size;
/**
* 构造具有初始化容量的数组
* 构建了元素数组
*/
public ArrayListInit(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);
}
}
/**
* 无参构造方法,第一次添加元素时初始化为10容量
*/
public ArrayListInit() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 把c转换为数组对象,赋值给elementData
*/
public ArrayListInit(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {//如果有元素
if (elementData.getClass() != Object[].class)//强转为Object.
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {//如果没有元素
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
/**
* 对ArrayList进行瘦身,有多少个元素,容量就变为多少
*/
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
/**
* 设置所需的最小容量
* 如果进行一次扩容后的容量小于minCapacity,
* 则把容量变成minCapacity,否则就是扩容后的容量
* @param minCapacity the desired minimum capacity
*/
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
? 0 : DEFAULT_CAPACITY;
if (minCapacity > minExpand) {//需要进行容量最小确认
ensureExplicitCapacity(minCapacity);
}
}
//确保容量不小于minCapacity,如果小于就扩容
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;//变动次数
// overflow-conscious code//扩充判断
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* list最大容量Integer.MAX_VALUE
* OutOfMemoryError: 超过Integer.MAX_VALUE才会内存溢出(实际上上超出就是负数了)
* hugeCapacity,最大的容量是Integer.MAX_VALUE
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 增加容量newCapacity = oldCapacity + (oldCapacity >> 1)
* 扩容为minCapacity或oldCapacity + (oldCapacity >> 1),谁大就是谁
* add元素时minCapacity=size+1;
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//可能会溢出
//正数带符号右移的值肯定是正值,所以oldCapacity+(oldCapacity>> 1)
//的结果可能超过int 可以表示的最大值,
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果newCapacity<minCapacity则newCapacity = minCapacity
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;//size+1
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);
}
//溢出检测,最大为Integer.MAX_VALUE,超出其实就是负数了就oom了
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
/**
*先确保容量不小于size + 1,再添加元素,直接通过数组下标赋值
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
/**
* 移除指定位置的元素
* @return 返回被移除的元素
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E remove(int index) {
rangeCheck(index);//溢出检测
modCount++;//变动次数
E oldValue = elementData(index);//返回时进行了强转
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}