ArrayList作为java中常用的集合类型有哪些特点需要我们了解呢?本文将基于jdk1.8源码来一步步列出ArrayList有哪些需要令人注意的要点。
ArrayList继承实现关系如下图:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
从该图我们可以看出,ArrayList实现了RandmoAccess接口,RandmoAcess接口实现如下:
public interface RandomAccess { }
RandmoAccess接口中实际上并无任何实现,该接口只是表示实现了该接口的类能够提供快速访问功能。
ArrayList实现了RandmoAccess接口代表能够进行快速访问,而ArrayList的快速访问功能实际上是靠数组实现的,下面是ArrayList中最重要的两个属性:
//ArrayList实际存数据的地方 transient Object[] elementData; //ArrayList的大小 private int size;
下面我们来看ArrayList的默认构造方法:
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
默认构造方法会将elementData属性赋为DEFAULTCAPACITY_EMPTY_ELEMENTDATA,其中DEFAULTCAPACITY_EMPTY_ELEMENTDATA属性是一个空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
接下来我们看ArrayList中的add和get方法:
public boolean add(E e) { //确认是否扩容 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } public E get(int index) { //检查是否越界 rangeCheck(index); return elementData(index); }
可以看出Arraylist底层是通过数组来操作的。
ArrayList使用默认构造器创建类时创建的是一个空的数组,那么ArrayList是如何能够使用add方法存数据的呢?我们可以详细看看add方法中的ensureCapacityInternal方法源码:
private void ensureCapacityInternal(int minCapacity) { ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { //DEFAULT_CAPACITY常量数值是10 return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } private void ensureExplicitCapacity(int minCapacity) { //记录修改次数 modCount++; if (minCapacity - elementData.length > 0) //扩容方法 grow(minCapacity); }
从以上源码可以看出当ArrayList为一个空数组时,会赋予一个默认的扩容大小10,然后再进扩容方法里扩容ArrayList,因此ArrayList使用默认构造器初始化时,不会立马初始化数组大小,而是等待调用add方法后才会进行初始化,且初始化大小为10。
我们可以查看ArrayList的grow方法来看看arrayList实际是如何扩容的:
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; //位运算1.5倍扩容 int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) //判断minCapacity是否超出最大整数值 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; }
以上代码分为如下几个步骤: