ArrayList使用无参构构造,第一次添加将ArrayList中存放数据的elementData容量扩容为10
从上面断点处进入ArrayList的无参构造中
//ArrayList的元素都被存储在elementData中 此处使用transient关键字代表该字段为瞬时态,无法序列化 transient Object[] elementData; //无参构造初始化赋值给elementData的空数组 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //ArrayList的无参构造 public ArrayList() { //将elementData赋值为空数组 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
第一次给arrayList添加元素
从上面断点中进入以下源码
//此处的modCount意义为arrayList被修改的次数 防止多线程操作ArrayList导致出现错误 protected transient int modCount = 0; //此处的size代表的是当前需要赋值的索引值,int类型默认为0 private int size; public boolean add(E e) { //被修改的次数加1 modCount++; //调用add方法 add(e, elementData, size); return true; }
从上面add(e, elementData, size);进入到下面的方法中
private void add(E e, Object[] elementData, int s) { //此处判断当前需要赋值的索引值是否等于elementData的长度 //如果相等的话,说明当前的elementData的容量不足了,需要进行扩容 if (s == elementData.length) //调用grow()函数对elementData进行扩容 elementData = grow(); //将需要添加的元素添加到elementData中 elementData[s] = e; //对size进行加1,为下一添加的元素的索引值 size = s + 1; }
上面代码中调用的grow()函数
private Object[] grow() { //上面代码中调用的grow()函数 return grow(size + 1); }
上面代码中进入的函数,第一次添加元素,走else
private static final int DEFAULT_CAPACITY = 10; //上面代码中进入的函数 //minCapacity此处为1 private Object[] grow(int minCapacity) { //目前的容量即elementData的当前长度 int oldCapacity = elementData.length; //如果当前的elementData不为无参构造所赋值的默认空数组进入if中,否则进入else if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //newCapacity为新的容量 大概意思为在oldCapacity的基础上在加上oldCapacity >> 1的值 //即相当于int newCapacity = oldCapacity + (oldCapacity >> 1) //也相当于int newCapacity = oldCapacity + oldCapacity * 0.5 //newCapacity为oldCapacity乘以1.5 int newCapacity = ArraysSupport.newLength(oldCapacity, minCapacity - oldCapacity, /* minimum growth */ oldCapacity >> 1 /* preferred growth */); return elementData = Arrays.copyOf(elementData, newCapacity); } else { //从DEFAULT_CAPACITY和minCapacity中取出最大数,创建数组 //因为只有elementData为无参构造所赋值的默认空数组才会进入这里 //说明当使用无参构造创建ArrayList时,当第一次添加元素时,会将容量扩容为10 return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)]; } }
从上面代码返回回去,到下面代码中,将元素添加到elementData中
private void add(E e, Object[] elementData, int s) { if (s == elementData.length) elementData = grow(); //将需要添加的元素添加到elementData中 elementData[s] = e; //对size进行加1,为下一添加的元素的索引值 size = s + 1; }
第一次添加元素,调用无参构造,将容量扩容为了10,若之后还需再次扩容,则会将容量扩展为原来的1.5倍
当不需要扩容时,会在下面的语句中直接进行元素的添加,并返回
private void add(E e, Object[] elementData, int s) { //此处判断当前需要赋值的索引值是否等于elementData的长度 //此时if语句不满足,直接进行赋值 if (s == elementData.length) elementData = grow(); //将需要添加的元素添加到elementData中 elementData[s] = e; //对size进行加1,为下一添加的元素的索引值 size = s + 1; }
中间一些步骤与上面相同,不同的只有扩容时不同,此处只展示扩容时,中间步骤跳过
//此时minCapacity为size加1,之前添加了10个元素,所以这里为11 private Object[] grow(int minCapacity) { //oldCapacity为当前elementData的长度即为10 int oldCapacity = elementData.length; //if判断满足,进入if中 if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //newCapacity为新的容量 大概意思为在oldCapacity的基础上在加上oldCapacity >> 1的值 //即相当于int newCapacity = oldCapacity + (oldCapacity >> 1) //也相当于int newCapacity = oldCapacity + oldCapacity * 0.5 //newCapacity为oldCapacity乘以1.5 int newCapacity = ArraysSupport.newLength(oldCapacity, minCapacity - oldCapacity, /* minimum growth */ oldCapacity >> 1 /* preferred growth */); //将得到的新的elementData返回 通过Arrays.copyOf得到的数组会保留之前的数据 return elementData = Arrays.copyOf(elementData, newCapacity); } else { return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)]; } }
如果使用指定容量的构造器,则初始elementData的容量为指定容量
从当前断点进入到有参构造中
private static final Object[] EMPTY_ELEMENTDATA = {}; //ArrayList有参构造 initialCapacity创建对象时传入的容量大小 public ArrayList(int initialCapacity) { //如果容量大小大于0,则创建指定容量的数组进行返回 if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; //如果容量大小等0,则创建的数组为空数组,与无参构造相同 } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
总结:
1、ArrayList中维护了一个Object类型的数组elementData
transient Object[] elementData;
2、当使用无参构造创建ArrayList对象时,则初始化的elementData容量为0,当添加第一个元素时,会扩容为10,如需再次扩容,则扩容为原来容量的1.5倍(代码中是在原来容量的基础上加上原来容量数右移1位)
3、当使用有参构造创建ArrayList对象时,则初始化的elementData容量为指定容量大小,如果需要再次扩容,则扩容为原来容量的1.5倍(代码中是在原来容量的基础上加上原来容量数右移1位)