add()方法
没有初始化容器数组长度大小的情况
List<Integer> list = new ArrayList<>();
list.add(1);
1.没有初始化list指定容量,我们可以看到初始化一个elementData 空数组。
2.add操作添加第一个元素,首先执行ensureCapacityInternal方法,minCapacity此时等于1,然后调用ensureExplicitCapacity方法,在执行这一步时候内部又进行了一个计算,调用方法calculateCapacity,参数1为数组对象elementData,参数2为minCapacity等于1.
3.calculateCapacity方法内部,先判断如果elementData 等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA,返回DEFAULT_CAPACITY和minCapacity三元运算的值。DEFAULT_CAPACITY=10,minCapacity=1.所以Math.max(DEFAULT_CAPACITY, minCapacity)返回10;
4.调用ensureExplicitCapacity(10),如果 minCapacity - elementData.length > 0,进入grow()。
5.grow()方法,如果newCapacity - minCapacity < 0成立, newCapacity = minCapacity;,那么newCapacity 就等于10;然后
经过elementData = Arrays.copyOf(elementData, newCapacity); 最后elementData 数组长度被赋值为10。
源码
transient Object[] elementData;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;// =0
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);
}
所以在初始化不指定容量的时候,添加第一个元素的时候,会默认数组长度为10;
当添加第11个元素的时候,此时minCapacity=11,oldCapacity =10,此时
int newCapacity = oldCapacity + (oldCapacity >> 1);
首先10>>1,是右移一位 ,10转为二进制0000 1010 右移1位 0000 0101 转成10进制等于5,所以newCapacity 此时就等于15;
newCapacity - minCapacity<0不成立,newCapacity - MAX_ARRAY_SIZE > 0也不成立,直接到 elementData = Arrays.copyOf(elementData, newCapacity);这一步,新的数组长度就是15;
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);
}
所以第一次扩容后数组的长度为15;
那么在添加第16个元素的时候,又要进入第二次扩容了,每次都是老的容量进行位运算,右移一位所以第二次扩容后数组的长度为22,在添加第23个元素,那么进行扩容后的长度就是22+22>>1等于33.。每次扩容后都是老容量的1.5倍大小。
核心代码就是下面这一行代码。int newCapacity = oldCapacity + (oldCapacity >> 1);
曾经面试碰到过一个题目
List<Integer> list = new ArrayList<>(20);
经历几次扩容?
答案是0
所以得出另外一个结论,采用有参构造,如果是初始化容器数组长度为给定值的时候,必须要大于给定值才会扩容。