ArrayList是数组实现的一个动态数组,同样也支持随机访问,与普通数组相比,它的容量可以动态增长,且支持泛型。
ArrayList实现了List接口,实现了对数组的添加、删除、修改、遍历等操作。
ArrayList是非线程安全的集合,多线程环境下建议使用CopyOnWriteArrayList
内部类
内部类 | 描述 |
---|---|
ArrayListSpliterator | 可分隔的并行迭代器 |
Itr | 迭代器 |
ListItr | 双向迭代器 |
SubList | 子列表 |
属性
/**
* 列表的初始大小
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 空数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 空元素数组
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 存放元素的数组
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* 元素个数
*/
private int size;
构造
ArrayList支持构造一个空的集合,或者通过一个Collection转换为ArrayList,也可以指定初始容量来创建一个ArrayList
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.
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// defend against c.toArray (incorrectly) not returning Object[]
// (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
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);
}
}
ArrayList的添加、修改、删除操作
扩容机制
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
// 当前数组已饱和,执行扩容
elementData = grow();
elementData[s] = e;
size = s + 1;
}
private Object[] grow(int minCapacity) {
// 获取新数组容量新建数组,在把旧数组拷贝进去
return elementData = Arrays.copyOf(elementData,newCapacity(minCapacity));
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 扩容为旧数组的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity <= 0) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
return Math.max(DEFAULT_CAPACITY, minCapacity);
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return minCapacity;
}
return (newCapacity - MAX_ARRAY_SIZE <= 0)
? newCapacity
: hugeCapacity(minCapacity);
}
根据源码分析可知,ArrayList在每次添加元素的时候检查数组是否饱和,如果饱和,则创建一个比旧数组容量大1.5倍的新数组,再把旧数组拷贝进新数组。
遍历
ArrayList支持五种元素遍历:
ArrayList<Integer> integers = new ArrayList<>();
IntStream.range(0, 100000).forEach(integers::add);
// 1.随机访问
for (int i = 0; i < integers.size(); i++);
// 2.增强for循环
for (Integer i : integers);
// 3.迭代器
Iterator<Integer> iterator = integers.iterator();
while (iterator.hasNext()){iterator.next();};
// 4.双向迭代器
ListIterator<Integer> listIterator = integers.listIterator();
while (listIterator.hasNext()){listIterator.next();};
// 5.Stream流
integers.forEach(x->{});
迭代并发修改
使用Iterator遍历集合元素时不支持通过集合对象修改该集合的长度,否则会抛出ConcurrentModificationException
并发修改异常。
ArrayList内部类Itr就是一个Iterator:
private class Itr implements Iterator<E> {
// 游标
int cursor;
// cursor前一个位置
int lastRet = -1;
// 获取Iterator对象时ArrayList对象的修改次数
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
// 检查expectedModCount, modCount是否相等,否则抛出并发修改异常
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
// 检查修改次数
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
我们可以看到,Itr的expectedModCount在创建Itr对象的时候就已经确定,不能使用ArrayList对象做添加、删除操作,是因为这两个操作都会改变modCount变量,每次做迭代调用next()
方法的时候都会检查modCount是否改变,如果改变,则会抛出异常。
如果在Iterator迭代时删除元素,必须使用Iterator提供的remove()
方法,表示删除当前迭代的元素。
但是通过ArrayList对象对象元素做更新,执行set(int index, E element)
不会有影响。
如果需要在迭代器中做添加、删除、修改,那么就要使用双向迭代器ListIterator,因为ListIterator不仅继承了Iterator,还实现了add(E e)
、set(E e)
方法。
toArray()异常
ArrayList中存在两个重载方法toArray()
,它们都是将ArrayList转化为数组,但是返回类型不一样,如果使用不当,可能会导致类型转换异常,因为Object[] toArray()
方法的返回数组类型为Object,不能再向下转型成目标类型。
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
toArray(T[] a)
需要一个泛型参数,用来确定转换后的数组类型:
ArrayList<Integer> integers = new ArrayList<>();
// 转换后的元素类型为Object
Object[] objects = integers.toArray();
// 指定类型
Integer[] integers1 = integers.toArray(new Integer[0]);