在研究ArrayList扩容过程之前,先看下ArrayList的几个参数和构造函数:
// 默认的list的长度10
private static final int DEFAULT_CAPACITY = 10;
// 空实例的共享空数组实例(有参构造函数使用),相比jdk1.7,这里是1.8版本优化,减少空数组产生
private static final Object[] EMPTY_ELEMENTDATA = {};
// 空实例的非共享数组(只有无参构造函数使用)
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 实际存储数据的对象
transient Object[] elementData;
// 数组长度
private int size;
无参构造:
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
有参构造函数1:
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);
}
}
1、初始长度大于0时,直接初始化一个当前长度的数组;
2、初始长度为0时,初始化一个空数组;
3、初始长度小于0时,抛出异常;
有参构造函数2:
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;
}
}
传参为一个集合对象,直接将传参对象转换为数组,并把引用赋值给elementData数组。
1、数组对象长度大于0时,根据传参对象构造一个数组;
2、如果传参对象集合对象长度为0,则直接把空对象EMPTY_ELEMENTDATA赋值给elementData。
下面进入正题:
重点分析add(E e)函数(扩容就发生在新增接口哦中)
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
重点阅读方法:
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
该方法将原数组长度加一作为扩容后的最小长度
如果是第一次向list中添加元素,则最小会把数组扩容为默认值10,(原来数组长度小于10),
通过Math.max(DEFAULT_CAPACITY, minCapacity)取DEFAULT_CAPACITY和minCapacity的最大值。
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(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);
}
这段主要是为了防止数组长度超过数组默认的长度
Integer.MAX_VALUE - 8;
这里还有个有意思的地方:
@Native public static final int MAX_VALUE = 0x7fffffff;
默认的Integer的最大长度为2的31次-1,但是java限制的最大长度还要再减去8,其中在最长数组变量上有这么一句注释:
Some VMs reserve some header words in an array.
大概意思是某些VMs在数组前面会有标记长度的标记,所以减去的8为就是存这些东西了。
所以java(1.8)的意思大概是:我们规定数组的长度就是这么长啊,如果你一定要超过最长我也让你设,你自己心里有数就行(别说我非要扣掉你一些啊)。
最后就是把旧的数组里的元素赋值到新的元素,整个扩容过程结束。