JDK1.8 之 ArrayList 源码浅析

  • ArrayList概述        

        注释是个好东西,首先我们通过源码里的注释来了解下这个集合的一些特性,直接粘贴+翻译(英文一般,借助Google翻译勉强读吧):

        Resizable-array implementation of the <tt>List</tt> interface.  Implements
 * all optional list operations, and permits all elements, including
 * <tt>null</tt>.  In addition to implementing the <tt>List</tt> interface,
 * this class provides methods to manipulate the size of the array that is
 * used internally to store the list.  (This class is roughly equivalent to

 * <tt>Vector</tt>, except that it is unsynchronized.)

        它是一个实现List接口的可变数组。实现了所有List的操作,并允许所欲元素包括null。除了实现List接口之外,它还提供了一些操作数组内部元素的方法。

        <p>The <tt>size</tt>, <tt>isEmpty</tt>, <tt>get</tt>, <tt>set</tt>,
 * <tt>iterator</tt>, and <tt>listIterator</tt> operations run in constant
 * time.  The <tt>add</tt> operation runs in <i>amortized constant time</i>,
 * that is, adding n elements requires O(n) time.  All of the other operations
 * run in linear time (roughly speaking).  The constant factor is low compared

 * to that for the <tt>LinkedList</tt> implementation.

        有长度、非空判断等一些操作方法。add N个元素要花费O(n)时间。其他操作大都如此,与LinkedList相比它的常数因子较低。

         <p>Each <tt>ArrayList</tt> instance has a <i>capacity</i>.  The capacity is
 * the size of the array used to store the elements in the list.  It is always
 * at least as large as the list size.  As elements are added to an ArrayList,
 * its capacity grows automatically.  The details of the growth policy are not
 * specified beyond the fact that adding an element has constant amortized

 * time cost.

        每个集合实例都有一个容量,这个容量大小是数组用来存放元素的,它通常至少是list的长度。当元素被增加到集合中它的容量是自增的。自增策略的细节不是超出添加元素....(意会。。)

        <p>An application can increase the capacity of an <tt>ArrayList</tt> instance
 * before adding a large number of elements using the <tt>ensureCapacity</tt>

 * operation.  This may reduce the amount of incremental reallocation.

          一个应用可以指定集合的容量,在通过ensureCapacity操作增加大量元素之前。这可能会减少递增式的再分配数量。

        <p><strong>Note that this implementation is not synchronized.</strong>
 * If multiple threads access an <tt>ArrayList</tt> instance concurrently,
 * and at least one of the threads modifies the list structurally, it
 * <i>must</i> be synchronized externally.  (A structural modification is
 * any operation that adds or deletes one or more elements, or explicitly
 * resizes the backing array; merely setting the value of an element is not
 * a structural modification.)  This is typically accomplished by

 * synchronizing on some object that naturally encapsulates the list.

           请注意,这个实现是不同步的。如果有多个线程访问集合并且最少有一个线程修改集合的结构,必须在外部实现同步。(结构修改是指任何添加、删除一个或多个元素、或者明确修改后备数组大小;仅仅设置一个元素的值不属于结构修改)这通常通过在一些自然封装列表的对象上进行同步(意会..)。

         If no such object exists, the list should be "wrapped" using the
 * {@link Collections#synchronizedList Collections.synchronizedList}
 * method.  This is best done at creation time, to prevent accidental
 * unsynchronized access to the list:<pre>

 *   List list = Collections.synchronizedList(new ArrayList(...));

         利用 Collections.synchronizedList来实现一个线程安全的集合(并发场景下我们可以用Java提供的并发类容器,详情自己查资料..) 

          <a name="fail-fast">
 * The iterators returned by this class's {@link #iterator() iterator} and
 * {@link #listIterator(int) listIterator} methods are <em>fail-fast</em>:</a>
 * if the list is structurally modified at any time after the iterator is
 * created, in any way except through the iterator's own
 * {@link ListIterator#remove() remove} or
 * {@link ListIterator#add(Object) add} methods, the iterator will throw a
 * {@link ConcurrentModificationException}.  Thus, in the face of
 * concurrent modification, the iterator fails quickly and cleanly, rather
 * than risking arbitrary, non-deterministic behavior at an undetermined

 * time in the future.

            ArrayList采用了快速失败(fail-fast)的机制,通过记录modCount参数来实现。在面对并发的修改时,迭代器很快就会完全失败,而不是冒着在将来某个不确定时间发生任意不确定行为的风险。

        <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
 * as it is, generally speaking, impossible to make any hard guarantees in the
 * presence of unsynchronized concurrent modification.  Fail-fast iterators
 * throw {@code ConcurrentModificationException} on a best-effort basis.
 * Therefore, it would be wrong to write a program that depended on this
 * exception for its correctness:  <i>the fail-fast behavior of iterators

 * should be used only to detect bugs.</i>

            注意这个快速失败机制在迭代中并不能保证就是这样,通常来讲在未同步并发修改时它并不能提供任何硬性保证。快速失败机制会尽最大努力抛出一个ConcurrentModificationException。因此需要为这类问题编写一个依赖的异常,正确的除外。这种快速失败行为只适用于检查Bug。

        (个人水平有限,海谅。。。。来看下代码部分)

  1.    ArrayList继承和实现
  2. ArrayList的元素在哪里维护         
    底层使用Object类型的数组来维护元素,源码如下 :
        /**
         * Default initial capacity.  默认初始容量
         */
        private static final int DEFAULT_CAPACITY = 10; 
    
        /**
         * Shared empty array instance used for empty instances. 空实例的共享空数组
         */
        private static final Object[] EMPTY_ELEMENTDATA = {};
    
        /**
         * Shared empty array instance used for default sized empty instances. We
         * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
         * first element is added.  共享一个空实例用以默认大小的空实例。我们将它与EMPTY_ELEMENTDATA区别开来,
         *                          以便了解当一个元素添加时它膨胀了多少
         */
        private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    
        /**
         * The array buffer into which the elements of the ArrayList are stored. //ArrayList的元素存储在其中的数组缓冲区
         * The capacity of the ArrayList is the length of this array buffer. Any
         * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
         * will be expanded to DEFAULT_CAPACITY when the first element is added.
         */  
         //   关于这个数组请转看  
        transient Object[] elementData; // non-private to simplify nested class access
         
        /**
         * The size of the ArrayList (the number of elements it contains).
         *
         * @serial
         */
        private int size;
  3. 构造方法 
     1)构造一个默认容量为10的空数组(其实是在第一次add操作时初始化10个长度的)
        
    /**
         * Constructs an empty list with an initial capacity of ten.
         */
        public ArrayList() {
            this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
        }
    2)构造一个指定初始容量的空数组
    /**
         * 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);
            }
        }
    
    
    只支持对象类型,不支持基本数据类型
        For example:
    3)构造一个包含指定元素集合的arrayList.
     /**
         * Constructs a list containing the elements of the specified
         * collection, in the order they are returned by the collection's
         * iterator.
         *
         * @param c the collection whose elements are to be placed into this list
         * @throws NullPointerException if the specified collection is null
         */
        public ArrayList(Collection<? extends E> c) {
            elementData = c.toArray();  //转数组
            if ((size = elementData.length) != 0) {  //赋值并判断
                // c.toArray might (incorrectly) not return Object[] (see 6260652)
                if (elementData.getClass() != Object[].class)
                    elementData = Arrays.copyOf(elementData, size, Object[].class);
            } else {
                // replace with empty array.
                this.elementData = EMPTY_ELEMENTDATA;
            }
        }
    
    
    


  4.  常用方法 以新增元素为例:
        
    public boolean add(E e) {
            ensureCapacityInternal(size + 1);  // Increments modCount!!  
            elementData[size++] = e;
            return true;
        }
       4.1  ensureCapacityInternal方法来保证内部容量
            
     private void ensureCapacityInternal(int minCapacity) {
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {  //如果默认是空的数组,则最小容量在默认10和入参中选择最大的
                minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
            }
    
            ensureExplicitCapacity(minCapacity);
        }
     
      private void ensureExplicitCapacity(int minCapacity) {
            modCount++;
    
            // overflow-conscious code
            if (minCapacity - elementData.length > 0)  //----如果数组的长度小于最小容量,则扩容
                grow(minCapacity);  //扩容方法
        }
    /**
         * 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;
             //---- 移位运算符,效率高。 相当于newCapacity =oldCapacity + 0.5 * oldCapacity
            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是新建一个newCapacity长度的新数组,并拷贝elementData数组。为了避免多次复制新建数组,应该提前预估长度,固定长度则可选用数组。


      循环中操作元素的办法
     


  5. ArrayList使用时要注意的问题    
    首先增加modCount来记录修改次数,然后赋值,然后返回个true。 注意循环操作时 ,详情转看
    多线程并发访问需要提供额外的同步机制。
  6.  总结 :

                    了解源码的目的就是为了更好地利用jdk提供的类,详情 转看    大笑

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值