目录
ArrayList 在 Collection 中的位置:
ArrayList 集合底层原理:
先总结:
ArrayList 底层是数组结构的:查找快,增删慢
看源码:
看一些重要的源码:
第一次存元素:
逻辑总览图:
长度为 10 的底层数组存满后继续存:
逻辑总览图:
ArrayList 在 Collection 中的位置:
因为 ArrayList 是 List 接口和 Collection 接口的实现类,所以它们的方法 ArrayList 也可以用。
ArrayList 集合底层原理:
先总结:
ArrayList 底层是数组结构的:查找快,增删慢
- 利用空参创建的集合,在底层会创建一个默认长度为 0 的数组(数组名: elementData)。
- 添加第一个元素时,底层会创建一个新的长度为 10 的数组。
- 存满时,若再添加元素,数组会扩容 1.5 倍。
- 如果一次添加多个元素,1.5 倍还放不下,则新创建数组的长度以实际为准,(也就是说 当添加元素个数超过了原来长度的一半时,就会以实际添加量为准进行扩容)
-
- 如图:
先看一些重要的源码:
1.首先找到 ArrayList-->Alt+7 看大纲 --> 找到空参构造
2.看到一个叫 "默认长度 _ 空 _元素数据" 赋值给了 “元素数据”
3.发现了 这个 "默认长度 _ 空 _元素数据" 的东西 其实是一个长度为 0 的数组
4.所以当空参创建集合对象时,此时集合元素的数量是 0
开始分析:
第一次存元素:
假设我们使用空参创建了一个集合,
并要添加一个元素“aaa”
1. 首先 add 方法接收参数,
并且 modCount++,表示集合操作次数加 1,
接着调用另一个 add 方法:
-
- 第一个参数是“aaa”
- 第二个参数是那个在创建集合时就已经创建好的的底层数组 elementDate
- 第三个参数是集合的长度,为 0
2.add 中的 add 方法:
因为 size 此时为 0,数组长度也为 0 所以进入 if 语句调用 grow()方法进行扩容
3.接着来看 grow 源码:
在 grow 内也调用了一个 grow 方法,并传入参数 1,
表示添加完当前元素之后的最小容量
4.grow 中的 grow 源码:
1 赋值给了 minCapacity
数组的长度到目前为止,没发生过变化,为 0
不满足 if 条件直接跳过,第一次添加数据的时候,会执行到else这里,
若在以后继续添加元素,就会执行 if 里面的代码
else 内将minCapacity 和DEFAULT_CAPACITY 进行了比较,看看DEFAULT_CAPACITY 内是什么
最后第二个 grow 方法原路返回一个长度为10的新数组,
5. 最后:
元素"aaa"放入底层新数组的 0 索引处,集合长度 size 变为 0+1=1。
逻辑总览图:
长度为 10 的底层数组存满后继续存:
现在假设之前底层创建的默认长度为 10 的数组已被存满了,
这时再存一个元素"aaa",看看底层逻辑是怎样的:
第一步还是看 add 方法:
首先 add 方法接收参数"aaa",
并且 modCount++,集合操作次数加 1,
接着调用另一个 add 方法:
-
- 第一个参数是“aaa”
- 第二个参数是 那个 存满 10 个元素的底层数组 elementDate
- 第三个参数是 集合的长度,为 10
2.add 中的 add 方法:
因为 size 此时为 10,数组长度也为 10, 所以进入 if 语句调用
grow()方法进行扩容:
3.现在看 grow 方法:
发现在 grow 内也调用了一个 grow 方法,并传入参数 11,
表示添加完当前元素之后的最小容量
4.grow 中的 grow 源码:
11 赋值给了 minCapacity
数组的长度到目前为止,没发生过变化,为 10,赋值给了old capacity 记录为老容量。
此时满足 if 条件(若是第一次存元素不会走 if),
在 if 内调用了一个Arrays Support 的 new Length 方法,并且传递了三个参数:
1.老容量
2. 理论增长容量 1,
3. 默认实际增长量是oldcapacity 进行右位移 1 的结果(10/21=5)。
我们来看看 newLength 方法:
(有个细节:这里为什么要将 minGrowth 和 preGrowth 进行比较
因为考虑到了一次添加多个元素的情况,如添加了一个长度为 100 的集合,这里的 minGrowth 就会是 100,经过比较最后取得增长量才会是 100,也就是说当添加元素个数超过了原来长度的一半时,就会以实际添加量为准进行扩容)
扩容后的长度用 preLength 接收,后面的 if 先不用看。
然后将扩容后的长度preLength =15 返回第二个 grow 方法的newCapacity 变量
然后调用了 Arrays 的 copyOf 方法:
根据长度 newCapacity :15创建新的数组
并把老数组中的所有数据全部拷贝到这个长度为 15 的新数组当中
最后将该数组原路返回
5.最后:
元素"aaa"放入底层新数组的 10 索引处,size 变为 10+1=11。