关于ArrayList
List概述
List是一个列表结构抽象定义,有序的,可对其中每个元素的插入位置进行精确地控制,可以通过索引来访问元素,遍历元素。包括函数的有:添加元素,删除元素,判断是否包含元素等等重要函数。
ArrayList
概述
ArrayList的底层数据结构是用数据结构实现得,申请的内存是连续得,访问数据比较快。添加元素时,如果JVM连续内存不足执行垃圾回收。添加元素大于数组大小,ArrayList会创建新数组并且老数组里元素复制到新数组中,然后添加新元素到最后一个元素后面。
类图
![](https://img2018.cnblogs.com/blog/1107906/201912/1107906-20191222180345091-625043236.png)
构造
实例化ArrayList对象时,并不知道要List的大小边界,此时可以使用一个无参数构造函数,ArrayList中有一个类型为Object[]的DEFAULTCAPACITY_EMPTY_ELEMENTDATA空数组,DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋值给元素存储对象数组elementData。
![](https://img2018.cnblogs.com/blog/1107906/201912/1107906-20191222180354839-24969855.png)
若知道边界大小实例化ArrayList时,使用带初始容量initalCapacity的构造函数。initalCapacity>0时,数组长度为initalCapacity;initalCapacity=0,数组为一个空数组;initalCapacity<0,抛出IllegalArgumentException异常。见如下源码:
![](https://img2018.cnblogs.com/blog/1107906/201912/1107906-20191222180406859-915336292.png)
size变量
指明ArrayList实例当前含有多少元素。
元素添加
使用无索引的add函数进行说明。首先ensureCapacityInternal函数确认内部容量大小
![](https://img2018.cnblogs.com/blog/1107906/201912/1107906-20191222180418770-1129807122.png)
ensureCapacityInternal 调用calculateCapacity函数计算容量大小。
![](https://img2018.cnblogs.com/blog/1107906/201912/1107906-20191222180434777-409714005.png)
calculateCapacity函数功能计𥫠算容量,elementData数组为空时,计算结果DEFAULT_CAPACITY和minCapacity其中最大值。
![](https://img2018.cnblogs.com/blog/1107906/201912/1107906-20191222180454846-1248482806.png)
ensureExplicitCapacity函数,modCount变量+1,minCapacity大于元素数组大小调用grow函数。
![](https://img2018.cnblogs.com/blog/1107906/201912/1107906-20191222180530795-2028026003.png)
grow函数:计算ArrayList容量公式:newCapacity = oldCapacity + (oldCapacity >> 1),即新容量大小=老容量大小*1.5。如果计算的newCapacity-minCapacity小于0,minCapacity 赋值给newCapacity;newCapacity-MAX_ARRAY_SIZE>0时,Integer.MAX_VAULE赋值给newCapacity。使用Arrays.copyOf函数把ArrayList元素复制到新数组中,新数组长度为newCapacity。
![](https://img2018.cnblogs.com/blog/1107906/201912/1107906-20191222180834509-514270996.png)
grow函数注意:
1)ArrayList是基于连续内存的数组结构,构造ArrayList实例时,最好能确认数组的边界避免减少数组复制,尤其ArrayList元素多时,调用add函数且大于容量大小时 ,非常耗时。
add带索引函数
rangeCheckForAdd函数检查索引。System.arraycopy函数移动元素,index索引元素及之后的元素都向后移一个位置。然后index索引位置放入element元素。
![](https://img2018.cnblogs.com/blog/1107906/201912/1107906-20191222180546093-1938013113.png)
索引获取元素
get函数传递index索引值获取元素
![](https://img2018.cnblogs.com/blog/1107906/201912/1107906-20191222180558703-493163214.png)
调用rangeCheck函数检查索引值,index值不能size变量,否则抛出IndexOutOfBoundsException异常。
![](https://img2018.cnblogs.com/blog/1107906/201912/1107906-20191222180611537-445375331.png)
elementData函数返回index索引对应的元素,并且转化E类型。
![](https://img2018.cnblogs.com/blog/1107906/201912/1107906-20191222180633376-550676464.png)
删除元素
remove(int index)
调用rangeCheck函数检查index索引。通过调用elementData函数获取被删元素,计算移动元素数量numMove=size-index-1,调用System.arraycopy函数移动元素。元素变量减少,size-1。size索引位置对应的设置为null.最后返回被删元素。
![](https://img2018.cnblogs.com/blog/1107906/201912/1107906-20191222180648180-151527471.png)
remove(Object o)
o为null时,比较元素值为null,调用fastRemove函数。o不为null时,比较o与元素哈希值,如果哈希值相等调用fastRemove函数。remove方法返回的boolean类型的值。
![](https://img2018.cnblogs.com/blog/1107906/201912/1107906-20191222180657865-1723792485.png)
fastRemove函数主要功能移动元素,size索引位置设置为null。size可以不设置null吗?其实是可以得,但不设置null,elementData引用已删元素,GC发现已删元素存在引用不会对元素进行回收。所以设置为null有利于GC回收,释放无用对象,有效利用内存空间。
![](https://img2018.cnblogs.com/blog/1107906/201912/1107906-20191222180707651-126197084.png)
总结
1)获取元素操作耗时少,响应快。
2)新增,删除操作时,若存在数组长度不够创建新数组的过程,耗时长,响应慢。尤其是大ArrayList实例场景。
重要辅助函数
System.arraycopy 元素移动
Arrays.copyOf ArrayList 转化成Object[]