zoukankan      html  css  js  c++  java
  • Java常见集合之ArrayList深入分析

    Java常见集合之ArrayList深入分析

    一、继承树

      

    二、ArrayList源码分析

    2.1  继承结构和层次关系

      

    2.2 源码分析:

      1 /*
      2 继承自AbstractList,实现了List、RandomAccess、Cloneable、Serializable接口
      3     1)RandomAccess接口:用来快速随机存取,在实现了该接口后,用普通for来遍历,性能更高
      4     2)Cloneable接口:实现了该接口,就可以使用Object.Clone()方法了
      5     3)Serializable接口:实现了该接口,表明该类可以被序列化
      6 */
      7 public class ArrayList<E> extends AbstractList<E>
      8         implements List<E>, RandomAccess, Cloneable, java.io.Serializable
      9 {
     10     //版本号
     11     private static final long serialVersionUID = 8683452581122892189L;
     12     //缺省容量
     13     private static final int DEFAULT_CAPACITY = 10;
     14     //缺省空对象数组
     15     private static final Object[] EMPTY_ELEMENTDATA = {};
     16     //默认大小的对象数组
     17     private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
     18     //元素数组
     19     transient Object[] elementData;
     20     //数组的大小
     21      private int size;
     22      
     23      //构造方法
     24      //无参构造 Constructs an empty list with an initial capacity of ten
     25      public ArrayList() {
     26         this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
     27     }
     28     
     29     /**
     30      * Constructs an empty list with the specified initial capacity.
     31      *
     32      * @param  initialCapacity  the initial capacity of the list
     33      * @throws IllegalArgumentException if the specified initial capacity
     34      *         is negative
     35      */
     36     public ArrayList(int initialCapacity) {
     37         if (initialCapacity > 0) {
     38             this.elementData = new Object[initialCapacity];
     39         } else if (initialCapacity == 0) {
     40             this.elementData = EMPTY_ELEMENTDATA;
     41         } else {
     42             throw new IllegalArgumentException("Illegal Capacity: "+
     43                                                initialCapacity);
     44         }
     45     }
     46     
     47      /**
     48      * Constructs a list containing the elements of the specified
     49      * collection, in the order they are returned by the collection's
     50      * iterator.
     51      *
     52      * @param c the collection whose elements are to be placed into this list
     53      * @throws NullPointerException if the specified collection is null
     54      */
     55     public ArrayList(Collection<? extends E> c) {
     56         elementData = c.toArray();    //转换为数组
     57         if ((size = elementData.length) != 0) {    //数组长度大于0
     58             // c.toArray might (incorrectly) not return Object[] (see 6260652)
     59             if (elementData.getClass() != Object[].class)    
     60                 elementData = Arrays.copyOf(elementData, size, Object[].class);
     61         } else {
     62             // replace with empty array.
     63             this.elementData = EMPTY_ELEMENTDATA;
     64         }
     65     }
     66     //总体而言:arrayList的构造方法就是做一件事,初始化一下储存数据的容器,
     67     //            其实本质就是一个数组,在其中就叫elementData
     68     
     69     //核心方法
     70     /**
     71      * Appends the specified element to the end of this list.
     72      * 默认直接在末尾添加元素
     73      *
     74      * @param e element to be appended to this list
     75      * @return <tt>true</tt> (as specified by {@link Collection#add})
     76      */
     77     public boolean add(E e) {    //elementData=[1,2,3] e=6
     78         //确保数组的容量足够
     79         ensureCapacityInternal(size + 1);  // Increments modCount!!
     80         //数组尾部添加元素e
     81         elementData[size++] = e;
     82         return true;
     83     }
     84     
     85     private void ensureCapacityInternal(int minCapacity) { //minCapacity=4
     87         ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
     88     }
     89     
     90     //计算容量
     91     private static int calculateCapacity(Object[] elementData, int minCapacity) {//elementData=[1,2,3],minCapacity=4
     92         //如果元素数组等于默认容量的元素数组,就返回DEFAULT_CAPACITY和minCapacity两者的最大值
     93         if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
     94             return Math.max(DEFAULT_CAPACITY, minCapacity);
     95         }
     96         //否则就返回minCapacity
     97         return minCapacity; //4
     98     }
     99     
    100     private void ensureExplicitCapacity(int minCapacity) { //minCapacity=4
    101         modCount++;
    102 
    103         // overflow-conscious code
    104         /*
    105         这里有两种情况:
    106             情况一:elementData为空数组,minCapacity=size+1=1,1-0>0,调用grow()进行扩容
    107             情况二:elementData不为空数组,minCapacity=size+1,为elementData原始的数组(未调用add方法前),
    108                     如果length不够用,再调用grow()进行扩容
    109         */
    110         if (minCapacity - elementData.length > 0)
    111             grow(minCapacity);
    112     }
    113     
    114     /**
    115      * 增加容量以确保它至少可以容纳由最小容量参数指定的元素数
    116      * Increases the capacity to ensure that it can hold at least the
    117      * number of elements specified by the minimum capacity argument.
    118      *
    119      * @param minCapacity the desired minimum capacity
    120      */
    121     private void grow(int minCapacity) {
    122         // overflow-conscious code
    123         //将原始的elementData.length赋给oldCapacity
    124         int oldCapacity = elementData.length;
    125         //新容量=1.5*oldCapacity
    126         int newCapacity = oldCapacity + (oldCapacity >> 1);
    127         //如果elementData为空数组,那么oldCapacity和newCapacity都为0,将newCapacity直接赋值为10
    128         if (newCapacity - minCapacity < 0)
    129             newCapacity = minCapacity;
    130         //如果newCapacity超过了最大的容量限制,将调用hugeCapacity()做进一步处理
    131         if (newCapacity - MAX_ARRAY_SIZE > 0)
    132             newCapacity = hugeCapacity(minCapacity);
    133         // minCapacity is usually close to size, so this is a win:
    134         //newCapacity确定好了以后,就copyof数组,进行扩容
    135         elementData = Arrays.copyOf(elementData, newCapacity);
    136     }
    137     
    138     private static int hugeCapacity(int minCapacity) {
    139         if (minCapacity < 0) // overflow
    140             throw new OutOfMemoryError();
    141         //判断minCapacity是否大于最大的数组容量MAX_ARRAY_SIZE:是,返回Integer.MAX_VALUE(2147483647);
    142         //否则返回MAX_ARRAY_SIZE
    143         return (minCapacity > MAX_ARRAY_SIZE) ?
    144             Integer.MAX_VALUE :
    145             MAX_ARRAY_SIZE;
    146     }
    147     
    148     /**
    149      * 在指定位置插入元素
    150      * Inserts the specified element at the specified position in this
    151      * list. Shifts the element currently at that position (if any) and
    152      * any subsequent elements to the right (adds one to their indices).
    153      *
    154      * @param index index at which the specified element is to be inserted
    155      * @param element element to be inserted
    156      * @throws IndexOutOfBoundsException {@inheritDoc}
    157      */
    158      public void add(int index, E element) {
    159         //检查插入的位置是否合理
    160         rangeCheckForAdd(index);
    161 
    162         //插入元素之后,将index之后的元素都往后移一位
    163         ensureCapacityInternal(size + 1);  // Increments modCount!!
    164         System.arraycopy(elementData, index, elementData, index + 1,
    165                          size - index);
    166         elementData[index] = element;
    167         size++;
    168     }
    169     
    170     /**
    171      * 用于add和addAll方法的范围检查
    172      * A version of rangeCheck used by add and addAll.
    173      */
    174     private void rangeCheckForAdd(int index) {
    175         if (index > size || index < 0)
    176             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    177     }
    178 
    179      /**
    180      * 删除指定位置的元素
    181      * Removes the element at the specified position in this list.
    182      * Shifts any subsequent elements to the left (subtracts one from their
    183      * indices).
    184      *
    185      * @param index the index of the element to be removed
    186      * @return the element that was removed from the list
    187      * @throws IndexOutOfBoundsException {@inheritDoc}
    188      */
    189     public E remove(int index) {
    190         //范围检查
    191         rangeCheck(index);
    192 
    193         modCount++;
    194         E oldValue = elementData(index); //要删除指定index位置的值
    195 
    196         //计算要移动的位数
    197         int numMoved = size - index - 1;
    198         if (numMoved > 0)
    199             /*
    200             public static native void arraycopy(Object src,  int  srcPos,
    201                                         Object dest, int destPos,
    202                                         int length);
    203             Copies an array from the specified source array, beginning at the
    204             specified position, to the specified position of the destination array.                            
    205             从源数组的特殊位置开始拷贝到目标数组的特定位置
    206 
    207             System.arraycopy(elementData, index+1, elementData, index,
    208                              size - index - 1);    //size=8,index=5,8-5-1=2,src=[1,2,3,4,5,7,8]
    209             */
    210             System.arraycopy(elementData, index+1, elementData, index,
    211                              numMoved);
    212         elementData[--size] = null; // clear to let GC do its work
    213 
    214         return oldValue;
    215     }
    216     
    217      /**
    218      * 移除list列表中第一次出现的待删除的元素
    219      * Removes the first occurrence of the specified element from this list,
    220      * if it is present.  If the list does not contain the element, it is
    221      * unchanged.  More formally, removes the element with the lowest index
    222      * <tt>i</tt> such that
    223      * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
    224      * (if such an element exists).  Returns <tt>true</tt> if this list
    225      * contained the specified element (or equivalently, if this list
    226      * changed as a result of the call).
    227      *
    228      * @param o element to be removed from this list, if present
    229      * @return <tt>true</tt> if this list contained the specified element
    230      */
    231     public boolean remove(Object o) {
    232         //依次遍历删除
    233         if (o == null) {
    234             for (int index = 0; index < size; index++)
    235                 if (elementData[index] == null) {
    236                     fastRemove(index);
    237                     return true;
    238                 }
    239         } else {
    240             for (int index = 0; index < size; index++)
    241                 if (o.equals(elementData[index])) {
    242                     fastRemove(index);
    243                     return true;
    244                 }
    245         }
    246         return false;
    247     }
    248     //remove函数用户移除指定下标的元素,此时会把指定下标到数组末尾的元素向前移动一个单位,
    249     //并把最后一个元素置为null
    250     
    251     /**
    252      * 将list表中指定位置的元素替换掉
    253      * Replaces the element at the specified position in this list with
    254      * the specified element.
    255      *
    256      * @param index index of the element to replace
    257      * @param element element to be stored at the specified position
    258      * @return the element previously at the specified position
    259      * @throws IndexOutOfBoundsException {@inheritDoc}
    260      */
    261     public E set(int index, E element) {
    262         //范围检查
    263         rangeCheck(index);
    264 
    265         //指定位置的元素值
    266         E oldValue = elementData(index);
    267         //将elementData的指定位置替换为element
    268         elementData[index] = element;
    269         return oldValue;
    270     }
    271     
    272     /**
    273      * 返回在list列表中的指定元素第一次出现的索引值
    274      * Returns the index of the first occurrence of the specified element
    275      * in this list, or -1 if this list does not contain the element.
    276      * More formally, returns the lowest index <tt>i</tt> such that
    277      * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
    278      * or -1 if there is no such index.
    279      */
    280     public int indexOf(Object o) {
    281         if (o == null) {
    282             for (int i = 0; i < size; i++)
    283                 if (elementData[i]==null)
    284                     return i;
    285         } else {
    286             for (int i = 0; i < size; i++)
    287                 if (o.equals(elementData[i]))
    288                     return i;
    289         }
    290         return -1;
    291     }
    292     //从头开始查找元素,可以查找null值
    293     
    294      /**
    295      * 返回在list列表中指定位置的元素
    296      * Returns the element at the specified position in this list.
    297      *
    298      * @param  index index of the element to return
    299      * @return the element at the specified position in this list
    300      * @throws IndexOutOfBoundsException {@inheritDoc}
    301      */
    302     public E get(int index) {
    303         //范围检查,只检查>=size的部分
    304         rangeCheck(index);
    305 
    306         return elementData(index);
    307     }
    308     
    309     E elementData(int index) {
    310         return (E) elementData[index];
    311     }
    312     //注意:返回的值都做了向下转型(object->E)处理
    313 }

    2.3 小结:

      1、ArrayList底层就是一个elementData数组,不过跟array相区别的是,它存在一个动态扩容机制

      2、由于每次添加、删除元素,都涉及到数组元素的移动,因此效率不高

      3、由于ArrayList实现了RandomAccess接口,适合做随机访问,用for循环进行查找元素,效率较高

     
     
  • 相关阅读:
    JPA的查询语言—使用构造器
    Servlet3.0使用注解定义Servlet
    jQuery操作<input type="radio">
    JPA的查询语言—使用原生SQL
    jQuery动态添加<input type="file">
    JPA的查询语言—JPQL的关联查询
    jQuery操作<select>
    Servlet3.0异步处理
    jQuery操作<input type="checkbox">
    mysql binlog二进制日志详解
  • 原文地址:https://www.cnblogs.com/xiaoguoniu/p/12633064.html
Copyright © 2011-2022 走看看