ArrayList 内部是以动态数组的形式来存储数据的。这里的动态数组不是意味着去改变原有内部生成的数组的长度、而是保留原有数组的引用、将其指向新生成的数组对象、这样会造成数组的长度可变的假象。 ArrayList 具有数组所具有的特性、通过索引支持随机访问、所以通过随机访问ArrayList中的元素效率非常高、但是执行插入、删除时效率比较底下 ArrayList 实现了 Serializable 接口,因此它支持序列化,能够通过序列化传输,实现了 RandomAccess 接口,支持快速随机访问,实际上就是通过下标序号进行快速访问,实现了 Cloneable 接口,能被克隆。 ArrayList 不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用 Collections.synchronizedList(List l) 函数返回一个线程安全的 ArrayList 类,也可以使用 concurrent 并发包下的 CopyOnWriteArrayList 类。 ArrayList部分源码如下:
public class ArrayList<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable,java.io.Serializable{
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
private transient Object[] elementData;
private int size;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
protected transient int modCount = 0;
}
复制代码
//方法一
public ArrayList(int initialCapacity)
//方法二
public ArrayList()
//方法三
public ArrayList(Collection<? extends E> c){
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
复制代码
Collection 类的实例,将该 Collection 实例转换为 ArrayList 对象 public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
复制代码
向ArrayList集合添加元素,最重要的方法是扩容数组
//方法一
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_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(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);
}
复制代码
newCapacity 为旧数组的1.5倍 newCapacity 比传入值 minCapacity 还要小,则使用传入 minCapacity ,若 newCapacity 比设定的最大数组容量大,则使用最大整数值 Arrays.copyof(elementData, newCapacity) 进行扩容 于此,add方法走的流程就是:先扩容,再赋值,然后返回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++;
}
复制代码
向指定位置添加元素:
rangeCheckForAdd
ArrayList在每次增加元素(可能是1个,也可能是一组)时,都要调用该方法来确保足够的容量。当容量不足以容纳当前的元素个数时,就设置新的容量为旧的容量的1.5倍加1,如果设置后的新容量还不够,则直接新容量设置为传入的参数(也就是所需的容量),而后用Arrays.copyof()方法将元素拷贝到新的数组。当容量不够时,每次增加元素,都要将原来的元素拷贝到一个新的数组中,这个操作代价很高,因此最好在创建ArrayList对象时就指定大概的容量大小,减少扩容操作的次数,或者使用LinkedList