arrayList原理分析从如下几个方面进行

1、继承关系

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

从上面的继承关系可以看出,ArrayList实现了List接口,继承AbstractList,而List又实现了Collection接口,另外它还实现了Cloneable和Serializable两个接口,支持克隆和序列化。

2、关键属性

private transient Object[] elementData;
private int size;

ArrayList很简单,它的存储结构就是一个数组结构,只是这个数组是动态数组,在空间不足的情况下可以自动扩容;另外虽然ArrayLIst是支持泛型的,但是底层存储的时候都会存储为Object类型,这个需要注意。

3、关键方法

1)添加元素时调用的grow方法

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);
    }

在数组添加元素时,需要进行容量检测,若当前数组长度不足以添加新的元素,则调用该方法对数组进行扩容,里面的关键方法是Arrays.copyOf方法,Arrays是一个方法类,提供了很多静态方法供数组使用,下面是它的实现

public static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
    }
    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

上面的代码没有什么特别的,最终是调用了System.arraycopy方法复制得到一个扩容后的新数组,System.arraycopy是一个native方法,native是java程序和C/C++程序的接口,它直接调用操作系统底层的方法,无需经过jvm转换,效率比java方法高;另外newType.getComponentType()方法需要注意,该方法是获取数组的元素的class对象的方法,利用反射Array.newInstance生成一个具体的对象数组。

2)转换为数组方法

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;
    }
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

toArray有两个方法,一个是带参数的,一个是不带参数的。从上面的分析知道,不带参数的toArray方法,最后返回的是Object对象的数组;带参数的toArray方法,最后返回的是具体参数类型的数组,这个在使用的时候我们就已经注意到了,不带参数的toArray方法转换为具体类型的数组会报错,原因就在toArray方法的实现里面。

3)add方法

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++;
    }

在某个位置添加元素,主要涉及到数组的移动,现在我们知道了为什么说数组的添加删除效率没有链表的高吧,因为内部涉及到数组的移位,数组移位的过程即数组拷贝的过程,只是源和目的都是同一个数组。

4)remove方法

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; // Let gc do its work

        return oldValue;
    }

在某个位置删除元素,主要也是数组元素位置移动,最终是要拷贝的方式实现,另外就是删除的数组元素会设置为null,防止内存泄露。


总结:arrayList实际上就是一个动态数组,内部的数组位置移动主要是利用system.arraycopy方法.