1.ArrayList介绍
ArrayList的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用ensureCapacity
操作来增加 ArrayList
实例的容量。这可以减少递增式再分配的数量。
ArrayList
继承了AbstractList
,实现了 List
, RandomAccess
, Cloneable
, java.io.Serializable
接口
特点
- Object[] 数组实现,默认大小为 10 ,支持随机访问,连续内存空间,
- 插入末尾时间复杂度 o(1),插入第 i 个位置时间复杂度 o(n - i)。(插入效率受插入位置影响)
- 扩容,大小变为 1.5 倍,调用Arrays.copyOf(底层 System.ArrayCopy),复制到新数组,指针指向新数组。(浅拷贝)不可指定扩容增长因子
- 线程不安全
1.1ArrayList与Vector的区别
ArrayList
是 List 的主要实现类,底层使用 Object[ ]存储,适用于频繁的查找工作,线程不安全 ;- Vector 是 List 的古老实现类,底层使用 Object[ ]存储,线程安全的。
1.2ArrayList与LinkedList对比
1.线程安全问题
ArrayList
与LinkedList
都是线程不安全的
2.底层数据结构
ArrayList
底层使用的是Object
存储元素,而LinkedList
底层使用的是双向链表
3.插入删除是否受元素位置影响
ArrayList
ArrayList
在执行默认插入方法add(E e)
时会默认将待插入元素追加到数组末尾,时间复杂度为O(1),而要在指定位置插入元素add(index i,E e)
就会受到元素位置影响 时间复杂度就为 O(n-i),因为要进行后续元素移位操作
LinkedList
LinkedList
使用链表存储元素,所以使用默认插入方法add(E e)
时间复杂度为O(1),而要在指定位置插入元素add(index i,E e)
则需要的时间复杂度为O(n),因为需要遍历到目标位置再进行插入
4.是否支持快速随机访问(下标访问)
ArrayList
支持快速随机访问,而LinkedList
不支持快速随机访问
5.内存空间占用
ArrayList
空间浪费主要体现在扩容后数组尾部会产生一定量的空节点
LinkedList
的空间浪费主要体现在每个节点都会占用较大的内存空间
2.核心源码
源码构造函数
/**
* Constructs an empty list with the specified initial capacity.
*
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*
*
* 带初始容量参数的构造函数
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) { //如果传入的参数大于0,创建initialCapacity大小的数组
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) { //等于0则取出空数组
this.elementData = EMPTY_ELEMENTDATA;
} else { //小于0则抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* Constructs an empty list with an initial capacity of ten.
* //默认的无参构造
* //集合创建时为空数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA长度为0,当第一个元素添加后扩容为10
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*
* 带有集合参数的构造,构造一个包含指定集合元素的ArrayList,顺序为参数集合的迭代器返回顺序
* 因为其中含有对参数的函数调用,所以可能会抛出空指针异常
*/
public ArrayList(Collection<? extends E> c) {
//集合转为数组
Object[] a = c.toArray();
if ((size = a.length) != 0) {//如果数组长度不为0
if (c.getClass() == ArrayList.class) {
//如果参数c为类型ArrayList就直接将参数集合数组赋给ArrayList元素数组
elementData = a;
} else {//c为其他类型
//将a数组拷贝给elementData数组
elementData = Arrays.copyOf(a, size, Object[].class);
}
} else {//数组长度为0
// 将空数组赋给elementdata元素数组
// replace with empty array.
elementData = EMPTY_ELEMENTDATA;
}
}
在执行无参构造arrayList
时,是初始化赋值了一个空数组,只有当真正的元素添加后才真正分配容量
扩容核心方法
/**
* Increases the capacity of this <tt>ArrayList</tt> instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity 所需最小容量
*
*/
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
//如果最小容量大于已有的最大容量
//判断是否需要扩容
ensureExplicitCapacity(minCapacity);
}
}
//计算容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//如果elementData为空返回默认扩容量或最小需求量的最大值
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
//不为空返回最小需求量
return minCapacity;
}
//作为扩容功能入口
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//判断是否需要扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0) //最小需要量大于数组长度(需要扩容)
//调用grow方法进行扩容,调用此方法代表已经开始扩容了
grow(minCapacity);
}
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
//要分配数组的最大的大小
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
//扩容核心方法
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length; //之前数组容量
int newCapacity = oldCapacity + (oldCapacity >> 1); //新容量设置为旧容量1.5倍
if (newCapacity - minCapacity < 0) //新容量是否大于最小需要量
newCapacity = minCapacity; //不是则将最小需要量作为新容量
if (newCapacity - MAX_ARRAY_SIZE > 0) //检查新容量是否大于最大容量
newCapacity = hugeCapacity(minCapacity); //若大于调用hugeCapacity获取新容量
// minCapacity is usually close to size, so this is a win:
//拷贝数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow 最小需要量为负导致数据溢出 抛出异常
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? //如果minCapacity大于MAX_ARRAY_SIZE,
// 则新容量则为Interger.MAX_VALUE,
// 否则,新容量大小则为 MAX_ARRAY_SIZE。
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
ensureCapacit方法
/**
* Increases the capacity of this <tt>ArrayList</tt> instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity 所需最小容量
*
*/
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
//如果最小容量大于已有的最大容量
//判断是否需要扩容
ensureExplicitCapacity(minCapacity);
}
}
ensureCapacit
在ArrayList
内部没有被调用过,所以这属于一个供用户调用的接口,作用是用户在大量元素添加之前,调用此方法预先扩容到近似容量以减少重新分配扩容的次数