概述
ArrayList就是动态数组,它提供了动态的增加和减少元素,实现了Collection和List接口,可以灵活的设置数组的大小。要注意的是ArrayList并不是线程安全的,因此一般建议在单线程中使用ArrayList。
数组:通过代码看得出来,新增,删除元素都可能伴随着内存拷贝,所以速度慢,但通过索引查找元素速度很快
我的版本是JDK 1.7,不同版本的源码不同
内存模型:
ArrayList底层是个object数组,还有个size,这俩变量很重要
初始化
初始化构建默认10个元素的数组
1.8以后初始化的时候默认构建空数组,在第一次add的时候才会扩容到10个长度数组
新增元素
新增元素(不传入元素增加的位置)
看容量够不够,不够的话扩容
将元素放到数组中,size+1
扩容逻辑
minCapacity是需要的最小容量,在新增一个元素时是size+1。如果数组的长度小于需要的最小荣浪(不够了)会扩容
扩容时,
- 根据元素数组的长度,计算出新的需要扩大到多少容量,计算逻辑:新增一半的容量(oldCapacity右移1就是除以2)。
- 如果计算出的结果newCapacity小于需要的最小容量minCapacity,就扩容到minCapacity,
- 如果计算出的结果newCapacity超过最大值2147483639(private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;)就扩展到指定的大小(具体看hugeCapacity函数)
- 将元素复制到新的数组中,注意,复制元素到数组涉及到内存复制,耗费资源,频繁进行这种动作速度会变慢,要是预计知道有多少个元素,在初始化的时候明确设置大小,避免自动扩容
新增元素(传入元素增加的位置)
这种方式会有内存拷贝,消耗资源较大,速度也慢,没有特别的需求别用这个
- 校验index不能大于size和不能小于0
- 扩容
- 数组的内存拷贝,将index之后的数据(index到结尾的所有数据),挪到elementData的index+1的位置,不需要新申请内存,但有内存拷贝,耗费资源
- 将传入的元素放到数组的制定位置,size++
删除元素
根据索引删除
除非删除结尾的元素,不然会有内存拷贝,速度慢
- 找到索引对应元素(用于返回)
- 计算需要挪的数据长度(如果删除的是最后一个就不需要内存拷贝),内存拷贝,从index+1的位置挪到index的位置
- 最后一个元素值为null
根据对象删除
遍历数组,找到对象后,拷贝数组内存,删除元素
查找数据
根据元素查找(返回索引)
分为是不是null,如果是null,看哪个元素等于null,如果不是null,根据equals判断是否相等
从0开始往后查,速度比较慢,还有个lastIndexOf函数从后往前差
根据索引查找
rangeCheck:检查下所以是否超过size
直接根据索引查找数组
设置数据
根据索引查找下老的元素,将新的元素替换到索引对应的位置
拷贝数据
clone是浅拷贝
修减容量trimToSize
ArrayList是动态扩容的,每次扩容都是1.5倍,到后来可能造成空间浪费,用这个函数可以缩减空间(有多少个元素申请多少空间,避免浪费),而且没有返回值,纯操作函数
马士兵老师Java集合全套视频_零基础Java小白必学框架源码教程:Hashmap底层原理分析——ArrayList,HashSet,List,TreeMap_哔哩哔哩_bilibili