实现方式:ArrayList是基于动态数组的方式实现的
以下是我对扩容的个人理解:
首先,在ArrayList类中,有无参构造和有参构造两种扩容方式。
1、无参构造:
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
通过无参构造方法创建对象后,默认的数组为空数组,之后调用add()方法添加元素时:在add()方法中调用ensureCapacityInternal()方法,在此方法中,判断数组是否为DEFAULTCAPACITY_EMPTY_ELEMENTDATA对象,既空数组。若为空,minCapacity值为1,DEFAULT_CAPACITY对象默认为10;将两者之间较大的数赋值给minCapacity。最后调用ensureExplicitCapacity()方法,并且传入新的minCapacity
2、有参构造:
传入的参数大于0,就创建一个以传入的initialCapacity大小的数组。如果等于0,创建的就是空数组,小于0,抛出异常
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);
}
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
ensureExplicitCapacity()方法:
判断最小需要容量(minCapacity)的数组长度(elementData):进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
通过grow()方法进行扩容:-->主要就是为了保证数组的长度>=最小需要的容量
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);
}
定义旧的容量=当前的数组长度
定义新的容量= 旧的容量移动一位。 整体相当于newCapacity =oldCapacity + 0.5 * oldCapacity
紧接着判断新的容量和最小的需要容量。
如果新的容量大于MAX_ARRAY_SIZE,就要把新的MAX_ARRAY_SIZE赋值给newCapacity。
总结:
通过无参构造的话,初始数组容量为0,当真正对数组进行添加时,才分配容量。每次按照1.5倍的大小扩容。最后使用 Arrays.copyOf 方法将原数组复制到新数组中,完成扩容操作。
无参构造方法创建的数,添加第一个元素时数组长度基本都扩容为10
扩容的核心方法为grow()方法。
注:
所创建的数组最大容量为MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8