ArrayList扩容原理
数据结构
ArrayList的底层数据结构是一个元素类型为Object的数组
构造方法
//默认容量
private static final int DEFAULT_CAPACITY = 10;
//用于空实例的共享空数组实例
private static final Object[] EMPTY_ELEMENTDATA = {};
//共享空数组实例,用于默认大小的空实例。 我们将其与EMPTY_ELEMENTDATA区分开来,以便知道在添加第一个元素时膨胀多少。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//数据缓冲区
transient Object[] elementData;
//数组列表长度
private int size;
//无参构造
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//int类型有参构造
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.当调用无参构造方法时,则将elementData的值设为DEFAULTCAPACITY_EMPTY_ELEMENTDATA。
2.当调用有参构造方法时,若参数大于0,则将elementData设为相应传参大小的Object数组,若参数为0,则将elementData设为EMPTY_ELEMENTDATA 。小于0,则抛出异常。
扩容机制
扩容一般发生在调用add方法向数组中添加元素的时候。
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
1.将当前数组长度size+1传入ensureCapacityInternal方法中,确保数组操作后能容纳下增加add后的值,若创建ArrayList时是无参构造,则将DEFAULT_CAPACITY(10)传入ensureExlicitCapacity方法中(创建长度为10的数组)
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
2.在ensureExplicitCapacity方法中,如果当前的数组需求容量(size+1)大于elementData的长度,则进入到grow方法
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
3.在grow方法中,newCapacity为将当前数组长度加上右移一位的长度(1.5倍)与传入的minCapacity比较,若minCapacity比较大,则将数组扩容到成minCapacity长度,(无参第一次扩容时)若newCapacity比较大,则将数组扩容到newCapacity长度(原数组扩容1.5倍的长度)
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);
}
示例
public static void main(String[] args) {
ArrayList<Object> objects = new ArrayList<>();
//当调用无参构造时,数组长度
System.out.println(getArrayListCapacity(objects));
objects.add(1);
//调用add方法
System.out.println(getArrayListCapacity(objects));
for (int i=0;i<10;i++){
objects.add(123);
}
System.out.println(getArrayListCapacity(objects));
ArrayList<Integer> arrayList = new ArrayList<>(12);
System.out.println(getArrayListCapacity(arrayList));
for(int i = 0;i <= 12;i++){
arrayList.add(456);
}
System.out.println(getArrayListCapacity(arrayList));
}
//反射获取数组长度
public static int getArrayListCapacity(ArrayList<?> arrayList){
Class<ArrayList> arrayListClass = ArrayList.class;
try {
Field field = arrayListClass.getDeclaredField("elementData");
field.setAccessible(true);
Object[] objects =(Object[]) field.get(arrayList);
return objects.length;
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
return -1;
}
}
输出
0
10
15
12
18