好久没写博客,一直是写在笔记上面。
我一直用的JDK8,所以今天的源码分析也是基于JDK8。
ArrayList简介
ArrayList 是一个动态数组队列。与Java中的数组相比,它的容量能动态增长。它继承于AbstractList,实现了List, RandomAccess, Cloneable, java.io.Serializable这些接口。
ArrayList 的爸爸是AbstractList,实现了List。AbstractList 提供了相关的添加、删除、修改、遍历等功能。
ArrayList 实现了RandmoAccess接口,支持快速随机访问。
ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。
ArrayList 实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输。
和Vector不同,ArrayList中的操作不是线程安全的!所以,建议在单线程中才使用ArrayList,而在多线程中可以选择Vector或者CopyOnWriteArrayList。
ArrayList的属性
- 序列化id
- 默认初始的容量
-
数组长度
-
.........
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
// 序列化id
private static final long serialVersionUID = 8683452581122892189L;
// 初始的容量(这里和Android Java不一样,Android是12)
private static final int DEFAULT_CAPACITY = 10;
// 一个空对象
private static final Object[] EMPTY_ELEMENTDATA = new Object[0];
// 一个空对象,如果使用默认构造函数创建,则默认对象内容默认是该值
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
// 当前数据对象存放地方,当前对象不参与序列化
transient Object[] elementData;
// 当前数组长度
private int size;
// 数组最大长度
private static final int MAX_ARRAY_SIZE = 2147483639;
}
ArrayList构造函数
-
默认构造函数
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//当进行第一次add的时候,elementData将会变成默认的增量长度:10.
-
int类型参数构造函数
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
-
Collection类型的参数构造函数
public ArrayList(Collection<? extends E> c) {
//将collection对象转换成数组,然后将数组的地址的赋给elementData。
elementData = c.toArray();
//如果它的长度不为0,进而判断它是否为Object类型的数组,如果不是的话,给它copyOf()为一个Object类型的数组。否则,给它置空。
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
ArrayList的方法
插入数据:add()方法
add方法:
- 确保数组已使用长度(size)加1之后的容量足够保存下一个数据
- 修改次数modCount 标识自增1,如果当前数组已使用长度(size)加1后的大于当前的数组长度,则调用grow方法,增长数组,grow方法会将当前数组的长度变为原来容量的1.5倍。
- 确保新增的数据有地方存储之后,则将新元素添加到位于size的位置上。
- 返回添加成功布尔值。
指定位置插入数据:add(int index, E element)方法
在指定位置添加元素:首先rangeCheckForAdd(index)判断索引是否超出数组下标,之后检测是否需要扩容,使用System.arraycopy 将需要插入的位置(index)后面的元素统统往后移动一位。将新的数据内容存放到数组的指定位置(index)上。
get方法:返回指定位置上的元素
set方法:更改指定位置的元素,并且返回旧元素
contains方法:调用indexOf方法,遍历数组中的每一个元素作对比,如果找到对于的元素,则返回true,没有找到则返回false。
remove方法:有两个,(1)根据索引移除元素;(2)根据对象移除元素
根据索引remove
索引没有越界时,操作数++,将指定位置(index)上的元素都往前移动一位,将最后面的一个元素置空,好让垃圾回收器回收,并且将原来的值oldValue返回
根据对象remove
循环遍历所有对象,得到对象所在索引位置,然后调用fastRemove方法,执行remove操作
clear方法:数组内的元素都置空,不减小数组容量。
trimToSize方法:将elementData的数组设置为ArrayList实际的容量,动态增长的多余容量被删除