一.简介
ArrayList 是 Java 集合框架中 List 接口的一个实现类。底层是数组,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。
ArrayList
是Vector
的翻版,区别在于ArrayList
是线程不安全的,而Vector
则是线程安全的。但是Vector
是一个较老的集合,具有很多缺点,不建议使用,这里我们就不对其进行分析了。
ArrayList 可以说是我们使用最多的 List 集合,它有以下特点:
- 它是基于数组实现的List类
- 可以动态地调整容量
- 有序的(元素输出顺序与输入顺序一致)
- 元素可以为 null
- 不同步,非线程安全,效率高
- 查询快,增删慢
- 占用空间更小,对比 LinkedList,不用占用额外空间维护链表结构
二.继承关系图
可以看到,ArrayList
是AbstractList
的子类,同时实现了List
接口。除此之外,它还实现了三个标识型接口,这几个接口都没有任何方法,仅作为标识表示实现类具备某项功能。RandomAccess
表示实现类支持快速随机访问,Cloneable
表示实现类支持克隆,具体表现为重写了clone
方法,java.io.Serializable
则表示支持序列化,如果需要对此过程自定义,可以重写writeObject
与readObject
方法。
三.成员变量
// 序列号
private static final long serialVersionUID = 8683452581122892189L;
// 数组初始容量为 10
private static final int DEFAULT_CAPACITY = 10;
// 空对象数组
private static final Object[] EMPTY_ELEMENTDATA = {
};
// 缺省空对象数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
};
// 底层数据结构,数组
transient Object[] elementData;
// 数组元素个数,默认为0
private int size;
// 最大数组容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
四.构造方法
//默认构造方法,初始为空数组。
//只有插入一条数据后才会扩展为10,而实际上默认是空的
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//根据指定容量创建对象数组
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
//创建initialCapacity大小的数组
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//创建空数组
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* 构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。
*/
public ArrayList(Collection<? extends E> c) {
//转换最主要的是toArray(),这在Collection中就定义了
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray 有可能不返回一个 Object 数组
if (elementData.getClass() != Object[].class)
//使用 Arrays.copy 方法拷创建一个 Object 数组
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 替换为空数组
this.elementData = EMPTY_ELEMENTDATA;
}
}
以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为10。
五.内部类
private class Itr implements Iterator<E>
private class ListItr extends Itr implements ListIterator<E>
private class SubList extends AbstractList<E> implements RandomAccess
static final class ArrayListSpliterator<E> implements Spliterator<E>
ArrayList有四个内部类,其中的Itr是实现了Iterator接口,同时重写了里面的hasNext(), next(), remove() 等方法;其中的ListItr 继承 Itr,实现了ListIterator接口,同时重写了hasPrevious(), nextIndex(), previousIndex(), previous(), set(E e), add(E e) 等方法,所以这也可以看出了 Iterator和ListIterator的区别:ListIterator在Iterator的基础上增加了添加对象,修改对象,逆向遍历等方法,这些是Iterator不能实现的。
六.核心方法
1.add()方法(有四个)
增和删是ArrayList
最重要的部分,这部分代码需要我们细细研究
//添加一个特定的元素到list的末尾
public boolean add(E e) {
//先确保elementData数组的长度足够,size是数组中数据的个数,因为要添加一个元素,所以size+1,先判断size+1的这个个数数组能否放得下,在这个方法中去判断数组长度是否够用
ensureCapacityInternal(size + 1); // Increments modCount!!
//在数据中正确的位置上放上元素e,并且size++
elementData[size++] = e;
return true;
}
//在指定位置添加一个元素
public void add(int index, E element) {
rangeCheckForAdd(index);
//先确保elementData数组的长度足够
ensureCapacityInternal(size + 1); // Increments modCount!!
//将数据整体向后移动一位,空出位置之后再插入,效率不太好
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
// 校验插入位置是否合理
private void rangeCheckForAdd(int index) {
//插入的位置肯定不能大于size 和小于0
if (index > size || index < 0)
//如果是,就报越界异常
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
//添加一个集合
public boolean addAll(Collection<? extends E> c) {
//把该集合转为对象数组
Object[] a = c