java arrayList 原理

来源:互联网 发布:郑州淘宝诈骗 编辑:程序博客网 时间:2024/04/29 21:53

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方法.










0 0
原创粉丝点击