ArrayList在集合框架中的树形结构
以继承和实现接口展示
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{}
优点
容量不固定,有最大阈值,但一般达不到
有序的(元素输出顺序与输入顺序一致)
元素可以为 null
效率高
size(), isEmpty(), get(), set() iterator(), ListIterator() 方法的时间复杂度都是 O(1)
add() 添加操作的时间复杂度平均为 O(n)
其他所有操作的时间复杂度几乎都是 O(n)
占用空间更小
对比 LinkedList,不用占用额外空间维护链表结构
源码分析
ArrayList底层实现是数组
transient Object[] elementData; // non-private to simplify nested class access
由于数组类型为 Object,所以允许添加 null 。
transient 说明这个数组无法序列化。
初始时为 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 。
private static final Object[] DEFAULTCAPACITY_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);
}
}
//初始为空数组
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//直接创建和指定集合一样内容的 ArrayList
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
添加元素
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//在指定位置添加一个元素
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
//整体后移一位
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
//挨个向后迁移
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
int numMoved = size - index;
//原来的数组挨个向后迁移
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
查询,修改等操作,直接根据角标对数组操作,都很快
E elementData(int index) {
return (E) elementData[index];
}
//获取
public E get(int index) {
rangeCheck(index);
//直接根据数组角标返回元素,快的一比
return elementData(index);
}
//修改
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
//直接对数组操作
elementData[index] = element;
//返回原来的值
return oldValue;
}
删除
以一个方法为例
//根据位置删除
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
//挨个往前移一位
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//原数组中最后一个元素删掉
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
注意
支持 RandomAccess 的对象,遍历时使用 get 比 迭代器更快。
由于 ArrayList 继承自 RandomAccess, 而且它的迭代器都是基于 ArrayList 的方法和数组直接操作,所以遍历时 get 的效率要 >= 迭代器。
另外,由于 ArrayList 不是同步的,所以在并发访问时,如果在迭代的同时有其他线程修改了 ArrayList, fail-fast 的迭代器 Iterator/ListIterator 会报 ConcurrentModificationException 错。
因此我们在并发环境下需要外部给 ArrayList 加个同步锁,或者直接在初始化时用 Collections.synchronizedList 方法进行包装
List list = Collections.synchronizedList(new ArrayList(...));