目录
前言
ArrayList是可以动态增长和缩减的索引序列,他是基于数组实现的list类。
- 不同于数组,ArrayList可以自增减
- ArrayList支持随机访问,查询效率高,增加、删除效率低
- 非线程安全
原码分析
接下来我们针对其原码做以下分析:继承关系、类中属性、构造函数、核心方法 四个方面分析
AbstractList:抽象类封装了通用的list集合操作
RandomAccess:标记接口,表明它们支持快速随机访问
Cloneable:支持接口,实现
Cloneable
接口,支持Object.clone()方法(CloneNotSupportedException
)java.io.Serializable:标记接口,支持序列化
继承关系
类中属性
- serialVersionUID:序列化编号
- DEFAULT_CAPACITY:集合的初始化容量
- DEFAULTCAPACITY_EMPTY_ELEMENTDATA:默认的空数组对象
- EMPTY_ELEMENTDATA:空数组对象
- MAX_ARRAY_SIZE:集合元素数组的最大值
- elementData:集合的元素数组对象
- size:集合的大小
- modCount:来源AbstractList,迭代器使用,多线程并发修改触发fail-fast机制
备注:elementData arrayList底层是数组,实际元素存在数组elementData;
modCount记录当前集合被修改的次数,当我们遍历集合时调用集合的add(),remove()等方法时,modecount值会被改变;而迭代器记录的还是原来的还是遍历之前的值,不一致则说明多个线程再同时操作集合,为了保证结果的准确性抛异常
ConcurrentModificationException
。
构造函数
核心方法
接下来我们从初始化、新增、修改、查询、删除分析下原码
/**
* ArrayList数据结构
* ArrayList底层是数组,集合的操似对数组的操作
* . 主要结构成员:DEFAULT_CAPACITY、elementData、size ...
* . 集合操作流程(初始化、增、删、改、查)
*/
@Test
public void testArrayList() {
//初始化
List list = new ArrayList();
//新增
list.add("a1");
log.info("添加元素a1到集合list:{}", list);
//修改
list.set(0, "a11");
log.info("修改位置为0的集合元素list:{}", list);
//查询
log.info("查询位置0的集合元素:{}", list.get(0));
//删除
list.remove(0);
log.info("删除集合元素后:{}", list);
}
//初始化 List list = new ArrayList();
无参构造函数构建一个默认容量为10的空集合;集合第一次添加元素方可同步默认容量;
//新增 list.add("a1");
List.add()会在集合数组的末尾添加元素E
- 确保添加元素后集合空间充足
- 计算集合保存元素需要空间,如果集合元素为缺省空数组,在默认容量DEFAULT_CAPACITY = 10和size+1之间取最大值;否则集合需要空间为size+1
- 集合修改次数modCount+1
- 判断是否需要扩容:如果size+1>elementData.length,执行扩容方法grow()
- 数组末尾添加新元素
- 当前集合的size+1
ensureCapacityInternal()方法
calculateCapacity()方法
ensureExplicitCapacity()方法
grow()方法
//修改 list.set(0, "a11");
- 获得索引的原元素
- 替换数组在当前索引的值为新元素
- 返回原元素
//查询 list.get(0) ;
//删除 list.remove(0);
- 验证删除的索引位置是否越界
- 修改计数器+1
- 查询当前修改位置的元素
- 计算需要移动的元素个数
- 索引之后的元素向前移动1位
- 集合的原最后位置赋值为null
- 返回删除的元素
总结
- ArrayList本质上是一个elementDate数组
- ArrayList集合的大小≠elementDate数组的长度
- ArrayList支持存放null
- ArrayList实现了RandomAccess,标记支持随机访问
- ArrayList由于底层是数组(固定长度),扩容或者缩容时会移动较多元素