文章目录
文章放置于:https://github.com/zgkaii/CS-Notes-Kz,欢迎批评指正!
1. AzrrayList 简介
java.util.ArrayList
是一个数组队列,相当于 动态数组。与Java中的数组相比,它具有容量能动态增长、元素增删慢、查找快的特点。
ArrayList
继承于 AbstractList
,实现了 List
、 RandomAccess
、 Cloneable
、java.io.Serializable
这些接口。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
--- omit ---
}
ArrayList
继承了AbstractList
抽象方法,实现了List接口,提供了相关的添加、删除、修改、遍历等功能。RandomAccess
是一个标志接口,表明实现这个这个接口的 List 集合是支持快速随机访问的。在ArrayList
中,我们即可以通过元素的序号快速获取元素对象,这就是快速随机访问。ArrayList
实现了Cloneable
接口,即覆盖了函数clone()
,能被克隆。ArrayList
实现了java.io.Serializable
接口,这意味着ArrayList
支持序列化,能通过序列化去传输。
Tips:
ArrayList
中的操作不是线程安全的!建议在单线程中才使用ArrayList
,多线程中选择使用Vector或者CopyOnWriteArrayList
。
2. ArrayList源码简析(JDK 1.8)
2.1 成员属性
// 默认容量大小
private static final int DEFAULT_CAPACITY = 10;
// ArrayList空实例共享的一个空数组
private static final Object[] EMPTY_ELEMENTDATA = {
};
// ArrayList空实例共享的一个空数组,用于默认大小的空实例。
// 与EMPTY_ELEMENTDATA分开,这样就可以了解当添加第一个元素时需要创建多大的空间。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
};
// 真正存储ArrayList中的元素的数组
transient Object[] elementData;
// ArrayList 所包含的元素个数,注意并不是elementData的长度
private int size;
// 数组的最大长度
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
AbstractList
抽象类中唯一属性:
// 表示elementData被修改的次数,每次add或者remove它的值都会加1
protected transient int modCount = 0;
为什么size不是用来标记elementData数组的长度呢?
在Java中,一般来说:
length
属性是针对数组而言的,比如下面源码中elementData.length
表示elementData
数组的长度。length()
方法是针对字符串而言的,可以调用length()
获取字符串长度。size()
方法是针对泛型集合而言的,可以调用size()
来获取集合中个数。
这样,就很好理解为什么size不是ArrayList的长度了,不易记混。
2.2 构造方法
ArrayList有三种初始化方式:
/**
* 有参的构造函数
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
// 初始化容量大于0,创建initialCapacity大小的数组
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// 初始化容量等于0,创建空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* 默认无参构造函数(未指定初始化容量大小),使用初始容量10构造一个空列表。
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 使用Collection集合来初始化ArrayList
*/
public ArrayList(Collection<? extends E> c) {
// 将集合转换为数组
elementData = c.toArray();
// 如果数组的长度size不等于0
if ((size = elementData.length) != 0) {
// 如果返回的不是Object类型数据
if (elementData.getClass() != Object[].class)
// 重新创建一个size大小的数组。
// 并将原来不是Object[]数组的内容,Copy给新的是Object[]的数组
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 用空数组代替
this.elementData = EMPTY_ELEMENTDATA;
}
}
从上面的分析中看出EMPTY_ELEMENTDATA与DEFAULTCAPACITY_EMPTY_ELEMENTDATA的区别。
EMPTY_ELEMENTDATA表示在我们实例化对象时指定了容量就是0,当添加1个元素后,那么elementData.length=1。
DEFAULTCAPACITY_EMPTY_ELEMENTDATA表示实例化时是无参构造,未指定容量,在调用add方法添加第1个元素后会默认扩容容量为10,即elementData.length=10。
2.3 添加元素
/**
* 直接将元素添加到数组末尾。
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return