??我们知道,Java中标准数组是定长的,在数组被创建之后,它们不能被加上或缩短。ArrayList是List接口的实现类,支持动态增长的数组。下面从源码了解ArrayList的扩容机制。
一、ArrayList的构造函数
??ArrayList有三种方式初始化,源码如下。
1.1 无参构造函数
??构造一个空列表,长度为0
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
1.2 带初识容量的构造函数
??用户自己指定初始容量
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.3 构造包含指定collection元素的列表
??通过集合的 Arrays.copyOf 方法复制返回
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
??可以看到,无参构造创建一个ArrayList时,实际上初始赋值是一个长度为0的空数组,当对数组进行添加元素时,才真正分配容量。
二、扩容过程
2.1 add()方法
??ArrayList扩容发生在add()方法调用的时候,每次调用add()方法,列表要求的最小容量+1
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
2.2 ensureCapacityInternal()方法
??内部调用的确认容量方法,此方法主要是为了确保当数组为空时,首次分配容量为10。
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
2.3 ensureExplicitCapacity()方法
??通过最小需求容量和现有容量对比,得出实际扩容量。
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
2.4 grow()方法
??ArrayList()实际的扩容方法,思路是每次扩容1.5倍。
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
??内部hugeCaoacity()方法
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
三、小结
|