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