最近有被问到ArrayList的扩容问题,决定学习一下ArrayList的源码。之前有在网上看到jdk6的分析好像是说在同构无参构造的时候就进行了初始容量的赋值。我这边只有jdk8,所以下面是一些我对于在jdk8中ArrayList扩容的理解。
首先点进ArrayList中的构造方法,发现并没有初始容量赋值的操作。
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
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 static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //空数组
transient Object[] elementData; //空数组
private static final int DEFAULT_CAPACITY = 10; //默认容量
在这个两个构造里面并没有看到直接初始容量的操作。
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
既然在初始化的时候没有初始容量,然后去add方法里面看看,这里面有个“确保内部容量”的ensureCapacityInternal()方法,点进去继续看
private void ensureCapacityInternal(int minCapacity) {
//第一次进来条件成立
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//10
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
public static int max(int a, int b) {
return (a >= b) ? a : b;
}
可以看出来,在第一次执行这个ensureCapacityInternal()方法时,可以看出来第一次执行的时候初始化数组的默认容量,接着看下面这个“确保明确容量”的ensureExplicitCapacity()方法
private void ensureExplicitCapacity(int minCapacity) { modCount++; // 假设第一次: 10>0 条件成立 if (minCapacity - elementData.length > 0) grow(minCapacity); }
接着继续看这个grow()方法
private void grow(int minCapacity) { // 假设第一次执行,oldCapacity=0,右移一位加上oldCapacity的newCapacity=0。 int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); //右移一位: oldCapacity/2 if (newCapacity - minCapacity < 0)//此时条件成立,将之前默认的10的容量赋值给这个newCapacity newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) //这个条件在数据量的很大的时候才能成立 newCapacity = hugeCapacity(minCapacity); //大数据量的时候会触发这个hugeCapacity()方法 // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); //最后会触发一个copyOf()的方法, }
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
ArrayList内部时数组结构的,数组的容量在初始化的时候就确定了并不能修改,所以这边的扩容,应该会是通过这个copyOf方法进行指定长度数组的赋值来实现ArrayList的动态扩容的。
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { @SuppressWarnings("unchecked") T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
在这个copyOf()方法之后,先是进行一个三元运算符的判断,由于这个newType是ArrayList中的Object数组,所以在这个判断条件的基础上前者成立,即T[] copy = new Object[newLength] . 最后调用System.arraycopy(原来的源数组,起始复制的坐标,复制的目标数组,开始复制的坐标,复制的长度)方法。将新数组复制成功。
以上如有问题,请不吝指正!
浙公网安备 33010602011771号