- 联系方式:1761430646@qq.com
- 菜狗摸索,有误勿喷,烦请联系
1. 接口实现
-
-
Serializable
:序列化接口 -
Cloneable
:克隆接口 -
RandomAcess
:这是一个标记接口,意味着实现此接口的类,具有可以快速随机访问的特点 -
List
:具有List
接口的特征
-
2. 基本属性
2.1 默认初始容量–DEFAULT_CAPACITY
-
这是数组初始化时的默认大小,但并不是空参初始化
ArrayList
时数组容量就直接赋予这么大,后面具体会讲
2.2 空数组实例–DEFAULTCAPACITY_EMPTY_ELEMENTDATA
-
这个【空数组实例】是专门用来进行无参构造
ArrayList
时的一个临时代替品,感觉这个其实没必要存在
2.3 实际装载元素的数组–elementData
-
存入
ArrayList
中的元素都是放置在此数组中,也正是如此,才会说ArrayList
的底层是由数组构成的 -
注意这是由
transient
修饰的,也即是对象序列化时此成员变量不会进行序列化操作,但实际上ArrayList
是重写了序列化与反序列化方法,实现自定义过程。其目的在于这个数组中可能会存在部分位置未存放元素,为了避免这些没有存储数据的内存空间被序列化
2.4 集合大小–size
-
这是集合大小,也即实际装载元素的数组中装载的元素的个数
2.5 数组容量最大值–MAX_ARRAY_SIZE
-
这个值代表的是数组的最大长度,也即意味着
ArrayList
能够装载的最大元素数量
3. 构造方法
3.1 无参构造方法
-
可以从源码中得知,当使用无参构造方法时,实际上是让装载元素的数组指向一个【空数组实例】,也就是说初始化的时候,数组长度为 0,而不是为 【默认的初始化容量】 10,后续存放元素进来时才会容量首次扩充为 10
- 这个
DEFAULTCAPACITY_EMPTY_ELEMENTDATA
就是一个【空数组实例】,跟EMPTY_ELEMENTDATA
一样,感觉这样没事定义一个【空数组实例】可能是为了进行语意上的区分
- 这个
3.2 指定大小的有参构造方法
-
注意一下,指定大小值为 0 时,会直接让
elementData
指向EMPTY_ELEMENTDATA
3.3 追加指定集合元素的有参构造方法
-
注意一下,指定集合为一个空集合时时,还是会直接让
elementData
指向EMPTY_ELEMENTDATA
4. 常用方法
4.1 扩充方法–grow
-
private void grow(int minCapacity) { // 获得当前数组实际存放元素的个数 int oldCapacity = elementData.length; // x = n + 0.5 * n,也就是得到一个按照 1.5 倍扩充的扩充值 int newCapacity = oldCapacity + (oldCapacity >> 1); // 如果扩充值比期望值小,那么扩充值 = 期望值,也就是此时按照期望值来扩充 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; // 如果扩充值 > 预期的最大值,那么就用 Integer 的最大值 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // 旧数组的元素复制到新长度数组中去 elementData = Arrays.copyOf(elementData, newCapacity); }
-
总结起来就是,扩充方法会接受一个预期值,在内部又会计算得到一个按照 1.5 倍扩充后的值,然后取两者种最大值作为实际扩充后的容量值
4.2 查找某个元素–find
-
可以看到,查找元素是区分元素是否为
null
来进行,并且是遍历数组,找到第一个即返回
4.3 往尾部添加元素–add
-
往数组尾部添加元素时会传一个【当前元素数量值 + 1】作为期望值去判断需不需要扩充先,然后再往尾部添加元素
4.4 往指定位置添加元素–add
-
可以看到会先对【指定位置值 index】做合法性检验,接着传一个【当前元素数量值 + 1】作为期望值去判断需不需要扩充先,然后就是对于【指定位置】后半部分的元素整体进行一次移动,最后才是设置【指定位置】的元素值,并且【size】+ 1
4.5 获取指定位置的元素–get
-
这个没啥好讲,先做个【索引值 index】合法性检验,然后直接在数组中取即可
4.6 删除指定位置的元素–remove
-
注意【指定位置】后面的元素会整体向前移动
4.7 序列化方法–writeObject
-
特别注意,只会序列化数组中的元素,后面的空位置不会理
5. 总结
-
虽然【默认初始容量】为 10,但是使用无参构造
ArrayList
时实际上指向的是一个【空数组实例】,也即此时数组长度为 0,并不是理所当然的 10,后续存放元素时才会首次扩充为 10 -
数组进行扩充时会传进来一个预期值,然后再会计算一个按照【当前存放元素数量 1.5 倍】扩充后的值,两者取最大值决定数组实际扩充后的容量大小
-
到某个位置上添加/删除元素时都会导致后面的元素整体移动一波
-
ArrayList
序列化时不会把这个数组序列化进去,而是序列化那些实际存在的元素而已