【集合】02 ArrayList原理深入解析

ArrayList就是数组列表,主要用来装载数据,当我们装载的是基本类型的数据int,long,boolean,short,byte…的时候我们只能存储他们对应的包装类,它的主要底层实现是数组Object[] elementData。

和LinkedList相比
LinkedList的底层是链表,所以拥有链表的特点,查询速度较数组慢,增删要快,而ArrayList的底层是数组实现的,增删慢,查询和访问元素的速度较快。

ArrayList的特点
增删慢,查询快,线程不安全,使用频率很高

ArrayList源码解析

1. ArrayList初始化分析

ArrayList初始化时,初始容量为0,只有真正对数据进行添加add时,才分配默认DEFAULT_CAPACITY = 10的初始容量。

分析

4个成员变量,下面的成员变量分别是默认容量、空对象数组、默认对象数组
在这里插入图片描述
从注释可以看出,elementData是一个对象数组缓存

在这里插入图片描述

1.1 有参构造函数

在这里插入图片描述
分析
可以看出,对于ArrayList,如果在new对象的时候传参数,也就是设置默认容量

如果默认容量大于0,elementData会指向一个容量为默认容量的对象数组

如果默认容量等于0,那么elementData会指向一个空对象数组的地址

如果默认容量小于0,因为容量不能为负,就会抛异常

1.2 无参构造函数

在这里插入图片描述
分析
可以看出,对于ArrayList,如果在new对象的时候不传参数,也就是不设置默认容量,那么elementData会指向一个默认空对象数组的地址

1.3 参数为集合的构造函数

在这里插入图片描述

2. ArrayList的add方法分析

数组的长度是有限制的,那么如果add元素超过了ArrayList容量会怎样呢?

下面是add方法的源码
在这里插入图片描述
ArrayList的增加元素时首先会调用方法 ensureCapacityInternal,去判断ArrayList的默认容量是否足够,如果不够就会扩容

我们先看看ensureCapacityInternal方法,参数minCapacity的值此时是传进来的size+1(size是int类型,初值为0)
在这里插入图片描述
继续点,看ensureExplicitCapacity方法
在这里插入图片描述
modCount用来记录修改次数,然后判断期望最小容量减去缓存数组的长度是否大于0
在这里插入图片描述

如果大于0,就调用grow方法,进行扩容

其实很好理解,因为第一次添加元素是,minCapacity的值是Size+1也就是1,第二次添加元素是2,也就是说minCapacity是存入元素的容量,所以也被称为期望最小容量,如果缓存数组的容量比期望的最小容量都要小,那么肯定放不下添加的元素,那么就必须调用grow方法进行扩容了。

3. ArrayList的扩容分析

数组的长度是有限制的,那么如果add元素超过了ArrayList容量会怎样呢?

在扩容的时候,老版本的jdk和8以后的版本是有区别的,8之后的效率更高了,采用了位运算,右移一位,其实就是除以2这个操作。

3.1 ArrayList的grow方法源码

在这里插入图片描述
从上文可知,minCapacity就是ArrayList添加元素之前的元素个数+1之后的期望最小容量(因为add每次只能添加一个元素,所以ArrayList的现在容量必须大于minCapacity,如果不大于就会扩容)

grow方法中,首先获取了扩容前的容量oldCapacity
在这里插入图片描述
新的容量为旧容量的1.5倍(旧容量加旧容量右移一位)
在这里插入图片描述
从这可以得出,ArrayList每次扩容都是原来的1.5倍,然后判断

如果新的容量减去期望最小容量小于0则新的容量就是最小期望容量

如果新的容量减去ArrayList的最大值也就是MAX_ARRAY_SIZE的话
在这里插入图片描述
看hugeCapacity方法
在这里插入图片描述
MAX_ARRAY_SIZE如下
在这里插入图片描述
Integer.MAX_VALUE如下
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/yujing1314/article/details/107425702
今日推荐