ArrayList是个动态数组,实现List接口,主要用来存储数据,如果存储基本类型的数据,如int,long,boolean,short,byte,那只存储它们对应的包装类。
增删慢:每次删除元素,都需要更改数组长度、拷贝以及移动元素位置。
查询快:由于数组在内存中是一块连续空间,因此可以根据地址+索引的方式快速获取对应位置上的元素。
ArrayList 是 Java 集合框架中的成员之一,底层是基于数组实现,并且集合容量可动态变化的。它继承自 AbstractList 抽象类,实现了 List 接口。同时还实现了 RandomAccess,Cloneable 和 Serializable 三个标记接口,说明 ArrayList 是支持快速随机访问,可克隆复制的,可序列化的。
- public class ArrayList
extends AbstractList - implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
- }
ArrayList是线程不安全的。
当开启多个线程操作List集合,向ArrayList中增加元素,同时去除元素。最后输出list中的所有数据,会出现几种情况:
① 有些元素输出为Null;
② 数组下标越界异常。
为什么ArrayList线程不安全,我们还使用它?
因为大多数的场景中,查询操作使用频率高,增删操作的使用频率低。如果涉及频繁的增删,可以使用LinkedList,实际开发过程中还是ArrayList使用最多的。 不存在一个集合既查询效率高,又增删效率高,还线程安全的,因为数据结构的特性就是优劣共存的,想找个平衡点很难,牺牲了性能,那就安全,牺牲了安全那就快速。
3.1 变量
ArrayList 底层是基于数组实现,并且集合容量可动态变化。类中定义了一个 Object 类型的数组存储元素,因为是 Object 类型的数组,所以也只能存储引用数据类型,如果存储基本数据类型(例如 int ,double等),底层会自动将基本数据类型进行类的包装。
ArrayList 中还定义了一个记录数组元素个数的变量,以及一个代表默认初始化容量的静态变量。
- /**
- * ArrayList 中存储元素的数组,数组的长度即集合的容量
- * 不用 private 关键字修饰是为了内部类方便访问此数组
- * transient 关键字修饰代表此数组不作为序列化的一部分
- */
- transient Object[] elementData;
- /**
- * 记录 ArrayList 集合中实际存储的元素个数
- */
- private int size;
- /**
- * 默认初始化容量
- */
- private static final int DEFAULT_CAPACITY = 10;
ArrayList 中定义了两个静态空数组对象,主要用来当集合初始化,并且没有添加任何元素时,作为一个空数组对象赋值给 elementData 数组对象,代表一个空 list。那为啥要定义2个空数组对象呢?后面会细讲。
- /**
- * 一个共享的静态空数组对象,用于空 list 集合中
- */
- private static final Object[] EMPTY_ELEMENTDATA = {};
- /**
- * 一个共享的静态空数组对象,用于默认大小初始化的空 list 集合中
- */
- private static final Object[] DEFAULTCAP