List --- ArrayList源码解析
程序员文章站
2024-01-03 09:02:40
...
本文采用的是jdk1.8,分析ArrayList常用的方法源码
一,ArrayList的关系图
在我们日常开发阶段,ArrayList是我们用的非常非常多的一个集合,带来了很大的便利,下面开始分析ArrayList的源码
二,源码分析
2.1属性分析
从ArrayList的属性,我们可以很清楚的看出:ArrayList的底层就是一个数组的形式,ArrayList中有扩容的概念,正式因为有扩容,所有它能实现动态增长
2.2 构造方法
2.3 add方法
add()方法是我们常用的方法,可以说是ArrayList比较重要的方法了,下面我们来看看:
2.3.1 add(E e)
步骤:
- 检查是否需要扩容
- 插入元素
首先先看看这个方法
public boolean add(E e) {
//确定list的容量,尝试容量加1
ensureCapacityInternal(size + 1); // Increments modCount!!
//添加元素
elementData[size++] = e;
return true;
}
这个方法主要就是干两件事:
- 确定list的容量,尝试容量+1,看有没有扩容的必要
- 添加元素
接下来进入ensureCapacityInternal()方法,看看容量的的添加过程
随后调用ensureExplicitCapacity()来确定明确的容量,我们也来看看这个方法是怎么实现的:
接下来看看grow()对数组的扩容过程
进入copyOf()方法看看是如何移动数组的
我们再进入arraycopy()里看看
该方法带有native修饰符,就可以知道是C/C++去写的,并非java来实现的,总的来说arraycopy()是一个比较高效可靠的方法
到目前为止,我们可以知道add(E e)的基本实现了:
>>首先去检查一下数组的容量是否足够
>>>>足够,直接添加元素
>>>>不足够,扩容数组
>>>>>>扩容都原来的1.5倍
>>>>>>第一次扩容后,如果容量还是小于minCapacity,就将容量扩充为minCapacity
2.3.2 add(int index, E element)
步骤:
- 检查角标
- 检查是否需要扩容
- 插入元素
下面这个是插入的实现:
2.4 get()
步骤:
- 检查角标
- 返回元素
接下来我们看看rangeCheck()和elementData()两个方法:
2.5 set(int index, E element)
步骤:
- 检查角标
- 替代元素
- 返回旧值
2.6 remove(int index)
步骤
- 检查角标
- 计算要移动的个数,并移动
- 将最后一个元素设为null(删除),让gc进行回收
2.7 细节说明
- ArrayList是基于动态数组实现的,在增删时候,需要数组的拷贝复制。
- ArrayList的默认初始化容量是10,每次扩容时候增加原先容量的一半,也就是变为原来的1.5倍
- 删除元素时不会减少容量,若希望减少容量则调用trimToSize()
- 它不是线程安全的。它能存放null值。