ArrayList的底层分析
ArrayList
ArrayList 是 Java 中常用的动态数组实现之一,它可以根据需要动态增长或缩减其大小。ArrayList
实现于 List
、RandomAccess
接口。可以插入空数据,也支持随机访问。ArrayList 内部使用数组来存储元素。初始时,ArrayList 的默认容量,当元素数量超过当前容量时,会自动进行扩容操作.
ArrayList
相当于动态数据,其中最重要的两个属性分别是: elementData
数组,以及 size
大小。 在调用 add()
方法的时候:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 递增!!
elementData[size++] = e;
return true;
}
- 首先进行扩容校验。当向 ArrayList 中添加元素时,会首先检查是否需要扩容。如果当前元素数量已经达到容量上限,就会进行扩容。
- 将插入的值放到尾部,并将 size + 1 。
如果是调用 add(index,e)
在指定位置添加的话:
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // 递增!!
//复制,向后移动
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
- 也是首先扩容校验。
- 接着对数据进行复制,目的是把 index 位置空出来放本次插入的数据,并将后面的数据向后移动一个位置。
其实扩容最终调用的代码:
private void grow(int minCapacity) {
// 溢出代码
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 超出了原数组中大小
elementData = Arrays.copyOf(elementData, newCapacity);
}
就是一个数组复制的过程。由此可见 ArrayList
的主要消耗是数组扩容以及在指定位置添加数据,在日常使用时最好是指定大小,尽量减少扩容。更要减少在指定位置插入数据的操作。
ArrayList 适合读取频繁、修改相对较少的场景,因为它的添加和删除操作可能会导致数组的拷贝操作。
ArrayList 不是线程安全的,如果在多线程环境下需要并发访问,可以考虑使用线程安全的替代类,如 Vector 或者使用 Collections 工具类中提供的线程安全方法进行包装。