ArrayList集合在创建对象后,其实在是在ArrayList类中是继承了一个类和实现了一些接口
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{}
在测试类中我们调用的是ArrayList类的无参构造
先写个测试类:
public static void main(String[] args) {
ArrayList<String> list= new ArrayList();
list.add("111");
list.add("222");
for (String str : list) {
System.out.println(str);
}
}
但是在ArrayList类中,我发现该无参构造又继续调用了本类的有参构造
无参构造:
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
有参构造:
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;
}
}
从无参构造中发现常量DEFAULTCAPACITY_EMPTY_ELEMENTDATA
赋给了变量elementData
,于是好奇的想知道该常量的声明,通过定位发现:
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
这是一个封装的Object
数组中的静态常量,并且该常量没有值,通过再次定位找到elementData
代码:
transient Object[] elementData;
transient
修饰的变量的elementData
不被序行化(暂且先记着,后续再提)
到了这里不难发现,一个没有值的常量赋给了elementData
,所以elementData
也是没有值的
再看下一个:
private int size;
此时的size
默认为0(切记)
回到测试类:
list.add("111");
由此时的add
定位到ArrayList
类的:
public boolean add(E e) {
ensureCapacityInternal(size + 1); //扩容, 因为size是没有值的,加1之后size的值为1,然后执行语句
elementData[size++] = e;
return true;
}
由ensureCapacityInternal
可以跳转到数组扩容的方法代码:
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
其中:
private static final int DEFAULT_CAPACITY = 10;
①判断是否相等,如果elementData
和DEFAULTCAPACITY_EMPTY_ELEMENTDATA
两值相同,则将得到的值放入判断执行代码块中Math.max()
将方法中的最大值赋给minCapacity
;②如果两值不相等,则直接调用ensureExplicitCapacity
方法,我通过该方法定位到下面扩容代码:
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)//如果条件符合,则执行扩容语句
grow(minCapacity);
}
但是我发现扩容也只是调用了grow
方法,于是再次定位到:
private void grow(int minCapacity) {
int oldCapacity = elementData.length; //数组的长度赋给旧数组的长度
int newCapacity = oldCapacity + (oldCapacity >> 1); //旧数组的值+旧数组一半的值=新数组的长度
if (newCapacity - minCapacity < 0) //如果新数组长度减去现有的数组长度小于0
newCapacity = minCapacity; //则现有长度就是新数组的长度(扩容失败)
if (newCapacity - MAX_ARRAY_SIZE > 0)//如果新数组长度减去最大数组长度大于0
newCapacity = hugeCapacity(minCapacity);//则最大值长度就是新数组的长度
elementData = Arrays.copyOf(elementData, newCapacity);
}
突然发现,这才是真正执行扩容的底层
当然我们也可以在创建对象的时候,就声明数组的长度,则此时用到的就是ArrayList
的有参构造了
ArrayList<String> list= new ArrayList<>(20);//我先设定长度为20
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);
}
}