ArrayList的继承体系
ArrayList 是 java 集合框架中比较常用的数据结构。继承自 AbstractList,实现了 List 接口。基于数组实现容量大小动态变化。同时还实现了 RandomAccess、Cloneable、Serializable 接口,所以ArrayList 是支持快速访问、复制、序列化的。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
ArraList的扩容机制
首先看下ArrayList的Add方法:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
其中ensureCapicityInternal()是添加元素时调用的扩容方法:
如果使用默认的构造参数的话,则选择minCapacity和DEFAULT_CAPACITY中较大的一个来作为最小的初始容量,大家可能奇怪,既然判断了初始化这一说,为何还会有传入的minCapacity,
和DEFAULT_CAPACITY比较这一说,是因为ensureCapacityInternal也会被addAll调用
解释:当集合对象第一次添加元素的时候,集合大小扩容为10(若使用addAll方法添加元素,则初始化大小为10和添加集合长度的较大值)
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);//非初始化状态时,判断集合是否需要扩容
}
当集合初始化完毕后,再次添加元素时。调用其ensureExplicitCapacity方法:
解释:if (minCapacity - elementData.length > 0),如果最小需要空间比elementData的内存空间要大,扩容,调用核心方法grow()
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
核心方法grow():
解释: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);(若预设值大于默认的最大值检查是否溢出)
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);
}
总结
- 1.ArrayList创建对象时,若未指定集合大小初始化大小为0;若已指定大小,集合大小为指定的大小;
- 2.当第一次调用add方法时,集合长度变为10和addAll内容之间的较大值;
- 3.之后再调用add方法,先将集合扩大1.5倍,如果仍然不够,新长度为传入集合大小;