从源码的角度简单理解 ArrayList 特性 (jdk 1.7,1.8)
先来说说ArrayList:
1.ArrayList实际上是通过一个数组去保存数据的,当我们构造ArrayList时,数组是没有初始化容量的。
2.当ArrayList 调用add方法的时候,会判断数据是否为空,如果为空,则初始化数组容量。长度为10.
3.ArrayList是线程不安全的。
4.当ArrayList容量不足以容纳全部元素时,ArrayList会自动扩张容量,新的容量 = 原始容量 + 原始容量 / 2(也就是自动扩容)
5. ArrayList的克隆函数,即是将全部元素克隆到一个数组中.
好了下面我们把这4句还原回去源码中,这样就可以让我们加速记忆:
ArrayList实际上是通过一个数组去保存数据的,当我们构造ArrayList时,数组是没有初始化容量的。
从源码可以看出
elementData 就是存储ArrayList的数组,从 DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; 可以看出 new ArrayList的时候是没有初始化的。
transient Object[] elementData; // non-private to simplify nested class access
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
当ArrayList 调用add方法的时候,会判断数据是否为空,如果为空,则初始化数组容量。长度为10.
当add方法进来后,会进入 ensureCapacityInternal 方法,然后再进入 calculateCapacity。然后判断当前数组为{},就会赋值
DEFAULT_CAPACITY 为初始化数组长度
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
private static final int DEFAULT_CAPACITY = 10;
transient Object[] elementData; // non-private to simplify nested class access
private int size;
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
ArrayList是线程不安全的:
在源码中可以看出 add方法是没有用到锁,如果多线程的情况下,会到造成线程安全问题!
当ArrayList容量不足以容纳全部元素时,ArrayList会自动扩张容量,新的容量 = 原始容量 + 原始容量 / 2(也就是自动扩容)
从代码可以看出当
minCapacity - elementData.length > 0 就调用 grow 方法。
minCapacity 当前要增加元素的位置,elementData.length 就是目前ArrayList 底层数组的容量,当
minCapacity > elementData.length 时,就代表 ArrayList 容量不够 ,调用grow方法,实现自动扩容。
然后我们来看看grow方法的实现
int oldCapacity = elementData.length; 就是目前ArrayList的容量
重点就是
oldCapacity >> 1 oldCapacity 向右移一位 就相当于 oldCapacity / 2 ,再加上本身。
所以
newCapacity 就是扩容后的数组容量大小
ArrayList的克隆函数,即是将全部元素克隆到一个数组中
elementData = Arrays.copyOf(elementData, newCapacity); 这个就是把原始的数组克隆到另一个已经扩容过的数组上,具体代码就不贴了,大家不懂的话,可以自行百度下,这个API也是比较简单的