public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { /** * 系列化ID. */ private static final long serialVersionUID = 8683452581122892189L; /** * 默认初始化容量. */ private static final int DEFAULT_CAPACITY = 10; /** * 用于空实例的共享空数组实例. */ private static final Object[] EMPTY_ELEMENTDATA = {}; /** * 共享的空数组实例,用于默认大小的空实例。咱们将此与EMPTY_ELEMENTDATA区别开来, 以了解添加第一个元素时须要膨胀多少。 */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; /** * 存储ArrayList的元素的数组缓冲区。 ArrayList的容量是此数组缓冲区的长度。添加第 一个元素时,任何具备elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空 ArrayList都将扩展为DEFAULT_CAPACITY。 */ transient Object[] elementData; /** * ArrayList的大小(它包含的元素数). * * @serial */ private int size;
以上属性注释都已经被翻译成中文,经过这些注释,咱们大概能了解到的一些有价值的信息java
ArrayList底层数据结构是一个Object数组数组
ArrayList的默认初始化容量为10数据结构
一个空的ArrayList集合在添加第一个元素时被扩容为10dom
ArrayList的大小是经过一个名为size的int变量存储的函数
源码继续往下看,先看ArrayList的构造函数源码分析
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); } } /** * 经过这里能够看出,当调用ArrayList的无参构造函数时,这个ArrayList的Object数组被初始化为 DEFAULTCAPACITY_EMPTY_ELEMENTDATA=10 */ public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } /** * Constructs a list containing the elements of the specified * collection, in the order they are returned by the collection's * iterator. * * @param c the collection whose elements are to be placed into this list * @throws NullPointerException if the specified collection is null */ public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // replace with empty array. this.elementData = EMPTY_ELEMENTDATA; } }
能够看到ArrayList一共有三个构造函数,一个无参构造,两个有参构造。this
当咱们在建立一个Arraylist集合时,若是不指定容量,也就是调用无参构造函数,那么这个Arraylist会被初始化为10.翻译
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
另外注意到另外两个有参构造,一个参数为int initialCapacity
,也就是咱们指定的初始化容量,这里对这个initialCapacity进行了一些简单的验证code
public ArrayList(int initialCapacity) { if (initialCapacity > 0) {//initialCapacity > 0 this.elementData = new Object[initialCapacity];//将一个容量为initialCapacity的新Object数组赋给elementData。 } else if (initialCapacity == 0) {//initialCapacity==0 this.elementData = EMPTY_ELEMENTDATA;//将EMPTY_ELEMENTDATA这个空object赋给elementData } else {//其余状况,也就是小于0,直接抛异常 throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } }
另外一个有参构造ci
public ArrayList(Collection<? extends E> c) { elementData = c.toArray();//将Collection集合转化为数组,而后赋给elementData这个object数组 if ((size = elementData.length) != 0) {//若是这个集合长度不为0 // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class)//若是集合转化后的数组不是Object数组 elementData = Arrays.copyOf(elementData, size, Object[].class);//转化为Object数组 } else {//其余状况,也就是elementData的长度为0嘛 // 替换为EMPTY_ELEMENTDATA空的数组 this.elementData = EMPTY_ELEMENTDATA; } }
能够看到这个构造函数,它是直接把一个Collection丢了进去,这也就是说,在new一个ArrayList时咱们能够把一个Collection集合放到参数列表中。
接下来再来看ArrayList的add方法
/** * 将元素添加到列表的末尾 * * @param e 要被追加到list中的元素 * @return <tt>true</tt> (as specified by {@link Collection#add}) */ public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e;//将元素e添加到数组中,下标为size++,其实也就是size,而后添加后size+1, return true; }
这里就两行代码,调用ensureCapacityInternal
这个方法,而且参数为size+1。点进去看下ensureCapacityInternal()
这个方法
/* 经过这个方法咱们能够看出,当咱们第一次调用add方法的时候,elementData数组的size为0,那么size+1就为1,因此minCapacity也为1,这里先经过一个if判断,判断minCapacity是否是一个空的object数组,若是是的话,minCapacity就取DEFAULT_CAPACITY和minCapacity的最大值,也就是10嘛 */ private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } //判断完以后进入了这个方法,同时参数为minCapacity,若是是第一次调用add方法的话参数为minCapacity就是默认大小10,不是第一次调用的话,就是size+1, ensureExplicitCapacity(minCapacity); } private void ensureExplicitCapacity(int minCapacity) { modCount++; //这个grow()就是扩容函数,如今minCapacity的话,仍是同样的分析,若是第一次调用add方法的话就是10,同时elementData.length为0,不是第一次调用的话minCapacity就是size+1,elementData.length也就是数组的长度为size if (minCapacity - elementData.length > 0) grow(minCapacity); }
读完这一段源码,能够得出如下结论
接下来咱们再来看下grow方法,了解一些Arraylist究竟是怎么样扩容的
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); //若是数组当前长度+数组当前长度/2 < 数组当前元素个数+1 if (newCapacity - minCapacity < 0) //就把数组当前元素个数+1赋给newCapacity newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // 最后咱们能够看到,这里进行了一个复制操做,将elementData里面的元素,复制到一个新的长度为newCapacity的Object数组,而后再把它赋给elementData elementData = Arrays.copyOf(elementData, newCapacity); }
这段代码应该很清晰吧,grow方法传进来的参数就是上面minCapacity,第一次调用add方法时是10,其余时候调用时是size+1(当前存储元素个数+1)
这里简单来讲就是将elementData当前长度给oldCapacity,而后newCapacity = oldCapacity + oldCapacity >> 1(左移操做,至关于除于2),若是oldCapacity = 10的话,newCapacity = 10 +(10/2),也就是15。经过以上代码,不难看出,ArrayList的扩容方法实际上就是将底层Object数组复制到了一个新的长度更长的数组里面去,而这个新数组的长度是原来的数组长度+原来数组长度的二分之一
,其实就能够说了扩容了1.5倍。
经过对以上源码进行分析,咱们能够得出如下结论了
总结:
elementData.length+1
个元素时会发生扩容,好比数组长度为10,在添加第11个元素时扩容原来数组长度+原来数组长度左移1位
完成,而不是直接经过乘法