zoukankan      html  css  js  c++  java
  • Java 集合系列(二)—— ArrayList

    ArrayList

      ArrayList 是通过一个数组来实现的,因此它是在连续的存储位置存放对象的引用,只不过它比 Array 更智能,能够根据集合长度进行自动扩容。

      假设让我们来实现一个简单的能够自动扩容的数组,我们最容易想到的点就是:

    1. add()的时候需要判断当前数组size+1是否等于此时定义的数组大小;
    2. 若小于直接添加即可;否则,需要先扩容再进行添加。

    实际上,ArrayList的内部实现原理也是这样子,我们可以来研究分析一下ArrayList的源码

     add(E e) 源码分析

     1   /**
     2      * Appends the specified element to the end of this list.
     3      *
     4      * @param e element to be appended to this list
     5      * @return <tt>true</tt> (as specified by {@link Collection#add})
     6      */
     7     public boolean add(E e) {
     8         ensureCapacityInternal(size + 1);   // 进行扩容校验
     9         elementData[size++] = e;            // 将值添加到数组后面,并将 size+1
    10         return true;
    11     }
    12 
    13 
    14 
    15     /**
    16      * The array buffer into which the elements of the ArrayList are stored.
    17      * The capacity of the ArrayList is the length of this array buffer. Any
    18      * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
    19      * will be expanded to DEFAULT_CAPACITY when the first element is added.
    20      */
    21     transient Object[] elementData; // non-private to simplify nested class access
    22     
    23     private void ensureCapacityInternal(int minCapacity) {
    24         ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));    // elementData 数组
    25     }
    26 
    27 
    28 
    29     /**
    30      * Default initial capacity.
    31      */
    32     private static final int DEFAULT_CAPACITY = 10;
    33     
    34     /**
    35      * Shared empty array instance used for default sized empty instances. We
    36      * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
    37      * first element is added.
    38      */
    39     private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    40 
    41     // 返回最大的 index
    42     private static int calculateCapacity(Object[] elementData, int minCapacity) {
    43         if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {   //  与空数组实例对比
    44             return Math.max(DEFAULT_CAPACITY, minCapacity);
    45         }
    46         return minCapacity;
    47     }
    48 
    49 
    50 
    51     private void ensureExplicitCapacity(int minCapacity) {
    52         modCount++;
    53 
    54         // overflow-conscious code
    55         if (minCapacity - elementData.length > 0)
    56             grow(minCapacity);
    57     }

    扩容调用方法,实际也就是数组复制的过程

     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     }

     add(int index, E element) 源码分析

     1   /**
     2      * Inserts the specified element at the specified position in this
     3      * list. Shifts the element currently at that position (if any) and
     4      * any subsequent elements to the right (adds one to their indices).
     5      *
     6      * @param index index at which the specified element is to be inserted
     7      * @param element element to be inserted
     8      * @throws IndexOutOfBoundsException {@inheritDoc}
     9      */
    10     public void add(int index, E element) {
    11         rangeCheckForAdd(index);    // 校验index是否超过当前定义的数组大小范围,超过则抛出 IndexOutOfBoundsException
    12 
    13         ensureCapacityInternal(size + 1);  // Increments modCount!!
    14         System.arraycopy(elementData, index, elementData, index + 1,
    15                          size - index);     // 复制,向后移动
    16         elementData[index] = element;
    17         size++;
    18     }
    19     
    20 
    21     /**
    22      * A version of rangeCheck used by add and addAll.
    23      */
    24     private void rangeCheckForAdd(int index) {
    25         if (index > size || index < 0)
    26             throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    27     }

    从上面的源码分析可知,扩容和随机插入元素的消耗比较大,因此在实际开发中,应尽量指定ArrayList大小,减少在随机插入操作。

    优缺点

    优点

    • 封装了一个动态再分配的对象数组
    • 使用索引进行随机访问效率高

    缺陷

    • 在数组中增删一个元素,所有元素都要往后往前移动,效率低下

    知识脑图

    在 github 上建了一个 repository ,Java Core Knowledge Tree,各位看官若是喜欢请给个star,以示鼓励,谢谢。
    https://github.com/suifeng412/JCKTree

    (以上是自己的一些见解,若有不足或者错误的地方请各位指出)

     作者:那一叶随风   http://www.cnblogs.com/phpstudy2015-6/

     原文地址: https://www.cnblogs.com/phpstudy2015-6/p/10618707.html

     声明:本博客文章为原创,只代表本人在工作学习中某一时间内总结的观点或结论。转载时请在文章页面明显位置给出原文链接

  • 相关阅读:
    svn command line tag
    MDbg.exe(.NET Framework 命令行调试程序)
    Microsoft Web Deployment Tool
    sql server CI
    VS 2010 One Click Deployment Issue “Application Validation did not succeed. Unable to continue”
    mshtml
    大厂程序员站错队被架空,只拿着五折工资!苟活和离职,如何选择?
    揭秘!Windows 为什么会蓝屏?微软程序员竟说是这个原因...
    喂!千万别忘了这个C语言知识!(~0 == -1 问题)
    Linux 比 Windows 更好,谁反对?我有13个赞成理由
  • 原文地址:https://www.cnblogs.com/phpstudy2015-6/p/10618707.html
Copyright © 2011-2022 走看看