jdk源码剖析之ArrayList

来源:互联网 发布:杰拉德华莱士数据 编辑:程序博客网 时间:2024/05/01 17:46

    ArrayList中最重要的是elementData数组和size,主要是通过数组实现。ArrayList中有几点细节需要了解:

1.创建对象时分配的空间。

    ArrayList的构造方法中并没有为elementData数组分配空间,而是在Add方法中判断当前ArrayList是否为空,若为空则分配DEFAULT_CAPACITY(10)的空间。

    /**     * Constructs an empty list with an initial capacity of ten.     */    public ArrayList() {        super();        this.elementData = EMPTY_ELEMENTDATA;    }    /**     * Appends the specified element to the end of this list.     *     * @param e element to be appended to this list     * @return <tt>true</tt> (as specified by {@link Collection#add})     */    public boolean add(E e) {        ensureCapacityInternal(size + 1);  // Increments modCount!!        elementData[size++] = e;        return true;    }    private void ensureCapacityInternal(int minCapacity) {        if (elementData == EMPTY_ELEMENTDATA) {            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);        }        ensureExplicitCapacity(minCapacity);    }

2.ArrayList数组空间分配的原则,数组大小增长的规律

    ArrayList中grow方法说明了数组大小的分配,当我们数组大小需要扩容的时候是通过扩大到原来的1.5倍来解决,若扩大到1.5倍无法解决问题,则直接扩大到我们需要的minCapacity,最后若minCapacity比我们配置的MAX_ARRAY_SIZE还要大,则扩展到Integer.MAX_VALUE。因此我们可以看出ArrayList支持的最大为Integer.MAX_VALUE,否则就会抛出OutOfMemoryError。

    /**     * Increases the capacity to ensure that it can hold at least the     * number of elements specified by the minimum capacity argument.     *     * @param minCapacity the desired minimum capacity     */    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);    }

3.elementData为何定义为transient?

    这是为了序列化是不序列化elementData,由于在elementData中有许多分配的空的空间,若进行序列化会造成空间的浪费。在序列化与反序列化过程中会调用writeObject和readObject方法,只会存有有效的信息。

    /**     * Save the state of the <tt>ArrayList</tt> instance to a stream (that     * is, serialize it).     *     * @serialData The length of the array backing the <tt>ArrayList</tt>     *             instance is emitted (int), followed by all of its elements     *             (each an <tt>Object</tt>) in the proper order.     */    private void writeObject(java.io.ObjectOutputStream s)        throws java.io.IOException{        // Write out element count, and any hidden stuff        int expectedModCount = modCount;        s.defaultWriteObject();        // Write out size as capacity for behavioural compatibility with clone()        s.writeInt(size);        // Write out all elements in the proper order.        for (int i=0; i<size; i++) {            s.writeObject(elementData[i]);        }        if (modCount != expectedModCount) {            throw new ConcurrentModificationException();        }    }    /**     * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,     * deserialize it).     */    private void readObject(java.io.ObjectInputStream s)        throws java.io.IOException, ClassNotFoundException {        elementData = EMPTY_ELEMENTDATA;        // Read in size, and any hidden stuff        s.defaultReadObject();        // Read in capacity        s.readInt(); // ignored        if (size > 0) {            // be like clone(), allocate array based upon size not capacity            ensureCapacityInternal(size);            Object[] a = elementData;            // Read in all elements in the proper order.            for (int i=0; i<size; i++) {                a[i] = s.readObject();            }        }    }

4.ArrayList的应用场景

    其应用场景其实就是数组的应用场景,适用于读多写少的场景,因为对于数组的读相对简单,依赖索引的读,其时间复杂度为O(1),但是数组依赖索引的写时间复杂度为O(n)。

                                             
0 0