1 构造器和添加元素
因为代码挺多的,所以分为几次来分析。首先先弄明白,使用的原理先,也就是先分析一下,ArrayList是怎么创建的、怎么添加元素先。
1. 2 构造器
平时创建一般都是直接new一个ArrayList的对象。下面来看一下,创建的几种方式,以及不同之处。
//带有初始容量的构造方法。
//如果参数大于0,则直接new一个大小一样的Object对象数组,此时容量就是你的初始值,非负数就行。
//如果等于0,引用一个空的Object数组。EMPTY_ELEMENTDATA
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);
}
}
//默认的构造方法,直接将存储数据的数据指向DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
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数组存储元素的是一个叫做elementData的引用,也就是一个Object类型的数组。
//一个空的数组对象
private static final Object[] EMPTY_ELEMENTDATA = {};
//一个空的数组对象
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//这是存储对象的真正引用
transient Object[] elementData;
可以看到,有两个不同的为空的数组对象引用。主要的区别就是,如果创建ArrayList的时候,如果指定了容量,就会创建一个相同大小的数组。如果指定容量为0,那么就直接引用 EMPTY_ELEMENTDATA。如果是默认创建的话,就直接引用DEFAULTCAPACITY_EMPTY_ELEMENTDATA。
这两者的主要区别就是前者前者添加第一个数据后扩容为1。后者在添加第一个元素后,会扩充容量为10。
下面就来讲解一些add()方法。
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
add方法比较简单。首先调用一个叫ensureCapacityInternal(size + 1)。size就是现在ArrayList内元素的个数。
private void ensureCapacityInternal(int minCapacity) {
//如果是使用无参构成创建的ArrayList对象
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//默认容量(10)和(当前大小+1)的比较
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
这个方法也比较简单,就是判断是不是使用无参构造创造的ArrayList对象。如果是的话,那么minCapcity就是赋值为10。
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 大小超过了容量,就要增长容量了
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
这个就是判断是否需要扩容。
看到这里,大家应该明白minCapcity是什么意思了。就是首先在添加元素的时候,先将当前的size+1进行探测,如果没有超过容量大小的话,就在数组后面添加元素,size加一。如果大于当前容量的话,就先扩容,调用grow方法,再添加数据。
2 扩容机制
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);
}
首先获得原来的容量大小。将容量扩容为原来的1.5倍。
int newCapacity = oldCapacity + (oldCapacity >> 1)
如果扩容的大小比探测的大小还小。探测大小就是扩容大小。主要情况有无参创建ArrayList的第一次add数据时和容量为0时。
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);
这两个就不用说了吧,就是已经到了最大容量情况和复制数组。
2.1 结论
就是ArrayList的扩容机制就是原来的1.5倍。特殊情况就是size+1(容量为0时)的情况和10(默认情况下)的情况