zoukankan      html  css  js  c++  java
  • 源码分析之ArrayList(未完待续,写到了274行)

    先看

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

    继承自AbstractList,实现了4个接口,List,RandomAccess,Cloneable,java.io.Serializable.

    List:这是一个序列,可以有重复元素。

    RandomAccess:可以随机快速访问的标记。

    Cloneable: 它实现了clone方法,可以合法地调用object.clone()方法。

    java.io.Serializable:支持序列化。

    1     /**
    2      * Default initial capacity.
    3      */
    4     private static final int DEFAULT_CAPACITY = 10;

    默认初始大小为10。

    1     /**
    2      * Shared empty array instance used for empty instances.
    3      */
    4     private static final Object[] EMPTY_ELEMENTDATA = {};

    为空的实例所共享的空数组实例

    1     /**
    2      * Shared empty array instance used for default sized empty instances. We
    3      * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
    4      * first element is added.
    5      */
    6     private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    用于默认大小的空实例的共享空数组实例。 将此与EMPTY_ELEMENTDATA区分开来,以了解添加第一个元素时要膨胀多少。

    1     /**
    2      * The array buffer into which the elements of the ArrayList are stored.
    3      * The capacity of the ArrayList is the length of this array buffer. Any
    4      * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
    5      * will be expanded to DEFAULT_CAPACITY when the first element is added.
    6      */
    7     transient Object[] elementData; // non-private to simplify nested class access

    可见ArrayList内部是用数组实现的。trasient 修饰符,这个属性不会被序列化。当第一个元素添加到空的ArrayList来的时候,这个数组会扩展到默认大小,也就是10.

    1     /**
    2      * The size of the ArrayList (the number of elements it contains).
    3      *
    4      * @serial
    5      */
    6     private int size;

    ArrayList的大小。也就是这个容器中元素的个数。

        /**
         * Constructs an empty list with the specified initial capacity.
         *
         * @param  initialCapacity  the initial capacity of the list
         * @throws IllegalArgumentException if the specified initial capacity
         *         is negative
         */
        public ArrayList(int initialCapacity) {
            if (initialCapacity > 0) {
                this.elementData = new Object[initialCapacity];
            } else if (initialCapacity == 0) {
                this.elementData = EMPTY_ELEMENTDATA;
            } else {
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
            }
        }

    这是ArrayList的一个带参构造方法,可以看到,初始容量不能为负,否则会主动抛出异常。这里,如果初始容量大于0,新建了一个Object数组并赋给了elementData。如果初始容量等于0,直接将EMPTY_ELEMENTDATA赋值给elementData。换句话说,在jdk1.8中,所有以带初始容量入参的构造方法创建的且传入的初始容量为0的ArrayList变量,指向的是同一个空的对象数组常量。

    1     /**
    2      * Constructs an empty list with an initial capacity of ten.
    3      */
    4     public ArrayList() {
    5         this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    6     }

    无参构造方法。会将DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋值给elementData.

     1     /**
     2      * Constructs a list containing the elements of the specified
     3      * collection, in the order they are returned by the collection's
     4      * iterator.
     5      *
     6      * @param c the collection whose elements are to be placed into this list
     7      * @throws NullPointerException if the specified collection is null
     8      */
     9     public ArrayList(Collection<? extends E> c) {
    10         elementData = c.toArray();
    11         if ((size = elementData.length) != 0) {
    12             // c.toArray might (incorrectly) not return Object[] (see 6260652)
    13             if (elementData.getClass() != Object[].class)
    14                 elementData = Arrays.copyOf(elementData, size, Object[].class);
    15         } else {
    16             // replace with empty array.
    17             this.elementData = EMPTY_ELEMENTDATA;
    18         }
    19     }

    一个带参的构造方法,可以传入E的子类组成的集合。elementData直接被赋值c.toArray()。如果这时它长度为0,

    会被替换成内部的EMPTY_ELEMENTDATA;如果长度不为0,进一步判断它的class是否为Object[].class,

    如果不是,则会用Arrays.copyOf()方法对其按照Object[]的class进行一次拷贝。

    PS:see 6260652指的是以前这个地方有bug,具体可以看:https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6260652

     1     /**
     2      * Trims the capacity of this <tt>ArrayList</tt> instance to be the
     3      * list's current size.  An application can use this operation to minimize
     4      * the storage of an <tt>ArrayList</tt> instance.
     5      */
     6     public void trimToSize() {
     7         modCount++;
     8         if (size < elementData.length) {
     9             elementData = (size == 0)
    10               ? EMPTY_ELEMENTDATA
    11               : Arrays.copyOf(elementData, size);
    12         }
    13     }

    调整ArrayList的容量为当前列表的大小。这个方法可以用来最小化ArrayList实例所占用的空间。

     1     /**
     2      * Increases the capacity of this <tt>ArrayList</tt> instance, if
     3      * necessary, to ensure that it can hold at least the number of elements
     4      * specified by the minimum capacity argument.
     5      *
     6      * @param   minCapacity   the desired minimum capacity
     7      */
     8     public void ensureCapacity(int minCapacity) {
     9         int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
    10             // any size if not default element table
    11             ? 0
    12             // larger than default for default empty table. It's already
    13             // supposed to be at default size.
    14             : DEFAULT_CAPACITY;
    15 
    16         if (minCapacity > minExpand) {
    17             ensureExplicitCapacity(minCapacity);
    18         }
    19     }

    增加ArrayList 实例的容量,如有必要,保证它至少可以容纳minCapacity(最小容量)个元素。minExpand(最小扩展)在elementData为空数据的时候为默认容量10,否则为0。当入参最小容量大于这个最小扩展时,会调用ensureExplicitCapacity()方法,并传入minCapacity。

    1     private static int calculateCapacity(Object[] elementData, int minCapacity) {
    2         if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
    3             return Math.max(DEFAULT_CAPACITY, minCapacity);
    4         }
    5         return minCapacity;
    6     }

    计算容量,如果elementData为空数据,返回初始容量10和minCapacity中的大者,否则直接返回minCapacity。

    1     private void ensureCapacityInternal(int minCapacity) {
    2         ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    3     }

    内部的保证容量的方法,先调calculateCapacity()计算容量,再调ensureExplicitCapacity()。

    1     private void ensureExplicitCapacity(int minCapacity) {
    2         modCount++;
    3 
    4         // overflow-conscious code
    5         if (minCapacity - elementData.length > 0)
    6             grow(minCapacity);
    7     }

    保证精确的容量,成员变量modCount自增一次,当最小容量大于elementData的长度时,调用grow(),并传入minCapacity。

        /**
         * The maximum size of array to allocate.
         * Some VMs reserve some header words in an array.
         * Attempts to allocate larger arrays may result in
         * OutOfMemoryError: Requested array size exceeds VM limit
         */
        private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    这个私有常量表明数组最大的长度可以为Integer的最大值减8,如果尝试分配更大的数组会引发内存溢出。

     1     /**
     2      * Increases the capacity to ensure that it can hold at least the
     3      * number of elements specified by the minimum capacity argument.
     4      *
     5      * @param minCapacity the desired minimum capacity
     6      */
     7     private void grow(int minCapacity) {
     8         // overflow-conscious code
     9         int oldCapacity = elementData.length;
    10         int newCapacity = oldCapacity + (oldCapacity >> 1);
    11         if (newCapacity - minCapacity < 0)
    12             newCapacity = minCapacity;
    13         if (newCapacity - MAX_ARRAY_SIZE > 0)
    14             newCapacity = hugeCapacity(minCapacity);
    15         // minCapacity is usually close to size, so this is a win:
    16         elementData = Arrays.copyOf(elementData, newCapacity);
    17     }

    grow()方法上面ensureExplicitCapacity()方法有调用。旧容量就是elementData的长度,新容量是老容量加老容量左移1位,就是1.5倍的样子。再看如果新容量小于最小容量,就取最小容量。如果新容量大于最大数组大小,就调hugeCapacity()计算一下。最后,将elementData按照上面得出的最小容量,进行一次拷贝。

    1     private static int hugeCapacity(int minCapacity) {
    2         if (minCapacity < 0) // overflow
    3             throw new OutOfMemoryError();
    4         return (minCapacity > MAX_ARRAY_SIZE) ?
    5             Integer.MAX_VALUE :
    6             MAX_ARRAY_SIZE;
    7     }

    大容量计算,如果minCapacity小于0,直接抛内存溢出error;再比较它与最大数组大小,小于则取整型最大值,超过了则取最大数组大小。

    .

  • 相关阅读:
    yii 引入文件
    CodeForces 621C Wet Shark and Flowers
    面试题题解
    POJ 2251 Dungeon Master
    HDU 5935 Car(模拟)
    HDU 5938 Four Operations(暴力枚举)
    CodeForces 722C Destroying Array(并查集)
    HDU 5547 Sudoku(dfs)
    HDU 5583 Kingdom of Black and White(模拟)
    HDU 5512 Pagodas(等差数列)
  • 原文地址:https://www.cnblogs.com/julymaple/p/4211614.html
Copyright © 2011-2022 走看看