一、概述
是一个数组队列,相当于动态数组。与一般数组不同的是,它的容量可以动态改变。
继承自AbstractList,实现了List、RandomAccess、java.io.Serializable、Clone接口。
Collection
表示高度抽象的集合接口,它包含了集合的基本操作:添加、删除、清空、遍历(读取)、是否为空、获取大小、是否保护某元素等等。
List
继承自Collection,表示有序集合,每个元素都有一个索引。添加了“添加、删除、获取、修改指定位置的元素”、“获取List中的子队列”等API接口。
CollectionAbstract
一个抽象类,它实现了Collection中除iterator()和size()之外的函数。
AbstractList
继承于AbstractCollection,并且实现List接口的抽象类。它实现了List中除size()、get(int location)之外的函数。
二、数据结构
数组,默认容量大小为10,类型为Object[],可动态扩展
private Object[] elementData; //用于存储数据
private int size; //用于记录当前有效数据数量
三、特点
- 有序
- 容量可变
- value可以为null
四、实现要点
1. 动态扩容/减少容量原理
ensureCapacity,扩展数组容量,每次尝试扩展1/2,如果仍然小于目标capacity,则直接设置为目标capacity。
调用时机:添加数据时,add(E e)
、add(int index, E e)
、addAll(Collection extends E> c)
、addAll(int index, Collection extends E> c)
方法会先调用ensureCapacity(newSize)
保证数组大小足够。
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != EMPTY_ELEMENTDATA)
// any size if real element table
? 0
// larger than default for empty table. It's already supposed to be
// at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 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) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
trimToSize,public方法,用于减少ArrayList所占内存。
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = Arrays.copyOf(elementData, size);
}
}
2. Iterato实现原理
Iterator中记录两个序号,当前元素序号(next()
方法返回元素序号)cursor,上次指向元素序号lastRef
Iterator方法:
next() 更新cursor和lastRef序号,lastRef=cursor,cursor+1,返回lastRef序号元素
hasNext() cursor < limit
-
remove() cursor指向lastRef,删除lastRef指向元素,并将lastRef置为-1
lastRef置为-1,保证多次调用lastRef相关方法不会影响到现有元素,直接抛出异常
ListIterator方法:
- previous() 更新cursor和lastRef序号,cursor-1,lastRef=cursor,返回lastRef序号元素
- hasPrevious() cursor != 0;
- set() 直接设置lastRet元素
- add() cursor位置插入元素,cursor+1,lastRef=-1
3. 线程安全性
对ArrayList的操作都是非线程安全的。如果需要在多线程环境下进行操作,可以使用
-
List list = Collections.synchronizedList(new ArrayList());
获取线程安全的ArrayList。 - 使用
CopyOnWriteArrayList
Collections.synchronizedList()通过重写ArrayList相关方法,添加一个互斥量mutex,方法调用之前都要尝试先去获取mutex
4. SubList
SubList 依赖parent的数据结构,根据parent的数据结构的不同SubList实现不一致
原理:
依然是使用原列表,内部维护一个指向parentList的引用。对SubList的操作会直接影响到parentList。
区别:
每次操作前都要检查本地modCount和原列表modCount,可能抛出ConcurrentModificationException。
使用场景:
使用 subList 处理局部列表。获取一堆数据后,需要删除某段数据。例如,有一个列表存在 1000 条记录,我们需要删除 100-200 位置处的数据:
list1.subList(100, 200).clear();
五、访问方式
ArrayList可以通过三种方式进行访问
Iterator,通过迭代器去遍历
Integer value = null;
Iterator iter = list.iterator();
while (iter.hasNext()) {
value = (Integer)iter.next();
}
RandomAccess,随机访问,通过索引值去遍历
Integer value = null;
int size = list.size();
for (int i=0; i
foreach循环遍历
Integer value = null;
for (Integer integ:list) {
value = integ;
}