ArrayList
可扩容数组原理的List实现类,实现类所有的List接口方法,并且允许插入null。Java语言中最常用的集合类。
源码分析
- ArrayList元素实际上保存在一个名字为elementData的Objec类型的数组内
- 无参构造器实例化时,elementData为{},默认的容量为10
- 第一次添加元素时,会先扩容
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) { //如果通过无参构造器实例化的,
//第一次添加元素时,
//判断成立,直接返回默认容量10,
//如果是通过有参构造器实例化的或者不是第一次添加元素,这里会直接返回传入的需要扩容的值,和默认容量值无关
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0) //扩容值超过数组长度,扩容
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //数组长度增大1.5倍
if (newCapacity - minCapacity < 0) //1.5倍增大后依然小于目标扩容值,直接按目标值扩容
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); //扩容
}
总结
- 如果使用无参构造器实例化的,添加第0个元素时,会直接走扩容流程,实例化一个长度为10的数组替换原有的elementData对象,继续添加第1-9个元素时,不会触发扩容,直到添加第10个元素时,开始扩容,实例化一个长度为15的数组替换原来elementData对象,往后,以此类推。。。
- 如果是使用的不是无参构造器实例化的,实例化时elementData对象就会有长度,假设实例化的长度为4,当添加第0-3个元素时,不会触发扩容,直到添加第4个元素时,才会将容量扩大为6,然后以此类推。。。
- 源码内部没有任何同步机制,所以ArrayList不是线程安全的
- 底层容器是数组,所以添加删除元素效率低,随机查询效率高,因为直接通过数组下标访问