ArrayList就是数组列表
与它类似的是LinkedList,和LinkedList相比,它的查找和访问元素的速度较快,但新增,删除的速度较慢。
从入口开始看起
public boolean add(E e) {
// 确保容量够 第一个数据为0 所以需要加1
ensureCapacityInternal(size + 1);
// 数组添加完第一位之后size自增1, 此处多线程有线程安全问题
elementData[size++] = e;
return true;
}
// 扩容检测
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
// 初始化容量判断, 如果数组为空,则默认给10个容量,否则为传入的容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
// 初始化容量之后
private void ensureExplicitCapacity(int minCapacity) {
// 用于记录数组修改的次数
modCount++;
// 传入容量大大于数组则需要扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
扩容逻辑
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 新容量要扩容一半
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果新容量小则新容量不变
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果新容量大于最大可申请容量(2^23-1-8)
// 则需要计算最大容量
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 将旧数据数据拷贝到新数组里面去
elementData = Arrays.copyOf(elementData, newCapacity);
}
总结:
ArrayList底层的数据结构是数组
ArrayList可以自动扩容,不传初始容量或者初始容量是0,都会初始化一个空数组,但是如果添加元素,会自动进行扩容,所以,创建ArrayList的时候,给初始容量是必要的
Arrays.asList()方法返回的是的Arrays内部的ArrayList,用的时候需要注意
subList()返回内部类,不能序列化,和ArrayList共用同一个数组
迭代删除要用,迭代器的remove方法,或者可以用倒序的for循环
ArrayList重写了序列化、反序列化方法,避免序列化、反序列化全部数组,浪费时间和空间
elementData不使用private修饰,可以简化内部类的访问