*注:本篇文章所用的java版本为java8,java8之前的arrayList
在单线程开发中,ArrayList是我们常用的容器之一,以下是个人对ArrayList底层创建数组和扩容的理解:
首先,我们打开ArrayList的源码进行查看,在这里我们先来查看ArrayList的初始化方法:
(重点关注无参和int型参的方法)
首先,我们先来查看ArrayList无参的方法
/**
* Constructs an empty list with an initial capacity of ten.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//ArrayList底层实际上就是围绕这这个名叫elementData的数组进行展开的
transient Object[] elementData;
public ArrayList() {
//当我们创建list时使用的是空参方法的话那就会直接给elementData附上初始值,注意:给数组赋值并不代表给了list一个初始长度,这也是jdk8和jdk7中list底层实现的一个很大的区别---jdk8在创建list的时候并不会去给list一个初始长度,而是在之后的add方法中赋予长度,但jdk7在你使用ArrayList的空参构造器初始化list的时候就赋予了list一个初始长度,长度为10.这里不多做赘述,有兴趣的朋友可自行参照jdk7中的list源码
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
可以看到,ArrayList底层就是数组,在初始化的时候也是在底层new的一个数组,但是arrayList数组的长度并不是在一开始就给你创建好的 我们继续往下看数组的add方法:
private int size;
//ArrayList添加内容的入口
public boolean add(E e) {
//size私有变量,每进一次方法size就会累加第一次进来就是初始值0
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
private static final int DEFAULT_CAPACITY = 10;
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//第一次进来的话minCapacity是1所以选择的肯定是第一个参数10
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
//每进一次方法都会递增
modCount++;
if (minCapacity - elementData.length > 0)
//真正给数组初始化长度和扩容的方法
grow(minCapacity);
}
private void grow(int minCapacity) {
//得到目前数组长度
int oldCapacity = elementData.length;
//给新的长度赋值:新容量等于老容量+老容量>>1(除以2)也就是1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果新的长度还小于传入的长度那么原封不动的把传入长度赋给新长度
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
//对新数组进行拷贝 elementData老数组的数据 newCapacity新数组的数据
//然后通过copyof进行拷贝,拷贝到一个新的数组中(第一次进入的时候就是创建一个为长度为10的数组而已 不要搞错了)这也是为什么说数组的增删效率低,因为实际上数组的增删实际上都是类似于这个的拷贝操作
elementData = Arrays.copyOf(elementData, newCapacity);
}
ok,上述内容就是一个ArrayList从初始化到添加对象到确定初始容量的一套流程了。重点在于add调用的grow方法,兼顾着初始化数组和扩容的两大职责若传入数组长度不大于10那么只是单纯的做拷贝工作往list里面添加内容,如果数组长度已经大于10了那么则会对当前数组扩容1.5倍并将原有的数组内容拷贝到扩容后的数组里。