ArrayList源码分析
以前,我刚开始学习JavaSe时,还不知道有ArrayList类。刚开始存多个元素时,都是使用数组。但感觉使用数组,不是那么方便。因为Java和php不一样(但和C一样),数组从定义起,其长度就被确定了,不能再被修改了。如果给数组长度定的太大,那么多余的空间浪费感觉挺可惜,但如果给小了,程序就会出问题。
等学习到了集合时,知道了有ArrayList,使用它时,我们不用费心思考虑到底给多个的容量,每次add时,它的容量会自动加1。
今天通过解读源码的方式,来说说ArrayList是如何进行扩容的。测试代码非常简单
ArrayList<String> hobbys = new ArrayList<>();
hobbys.add("动漫1");
hobbys.add("动漫2");
hobbys.add("动漫3");
hobbys.add("动漫4");
hobbys.add("动漫5");
hobbys.add("动漫6");
hobbys.add("动漫7");
hobbys.add("动漫8");
hobbys.add("动漫9");
hobbys.add("动漫10");
hobbys.add("动漫11");
当我们使用空参构造器创建实例时,会进行以下操作。
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
注意这个elementData,它就是用来保存元素的容器的。该变量类型是一个数组。
DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个空数组。
所以,这个时候,elementData数组的长度和元素个数都为0。
接下来执行
hobbys.add("动漫1");
在Arraylist的add方法体内容如下:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
ensureCapacityInternal(int length),方法用来确保elementData数组长度不能小于length。如果当前数组长度小于length的话,会执行内部扩容操作。
size属性初始值为0,它用来表示容器内的元素个数。
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
当elementData数组长度为0时,将会执行
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
这个时候minCapacity长度为DEFAULT_CAPACITY,该值为10.
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
minCapacity肯定比elementData.length大,所以执行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);
}
一般情况下,扩容的大小为原来长度的1.5倍。但是,刚开始的情况下,elementData的长度为0,扩容1.5倍还是0。所以,会拿该值和最小默认扩容值(10)进行比较。取两者中大的值进行扩容。
而最最核心的扩容代码如下
elementData = Arrays.copyOf(elementData, newCapacity);