zoukankan      html  css  js  c++  java
  • 深入理解JAVA集合系列四:ArrayList源码解读

    在开始本章内容之前,这里先简单介绍下List的相关内容。

    List的简单介绍

    有序的collection,用户可以对列表中每个元素的插入位置进行精确的控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。列表通常允许重复的元素,且允许null元素的存放。

    ArrayList的简单介绍

    JDK中这样定义ArrayList:List接口的大小可变数据的实现。

    主要有以下特点:

    1、有序

    2、线程不安全

    3、元素可以重复

    4、可以存放null值

    顾名思义,取名ArrayList是因为其内部是用一个大小可变的数组存储元素,也就是说底层是一个动态数组。

    add方法解读

    List<String> li = new ArrayList<String>();
    li.add("33");

    先看这个构造函数:

     public ArrayList() {
        this(10);
        }
    复制代码
    1  public ArrayList(int initialCapacity) {
    2     super();
    3         if (initialCapacity < 0)
    4             throw new IllegalArgumentException("Illegal Capacity: "+
    5                                                initialCapacity);
    6     this.elementData = new Object[initialCapacity];
    7     }
    复制代码

    这里先定义默认的初始容量为10,然后构建了一个容量为10的数组elementData;这个elementData数组就是ArrayList底层存放元素的数组,且元素是Object类型。该数组的源码定义也了解下:

    private transient Object[] elementData;

    再来看ADD方法:

    复制代码
     1 public void add(int index, E element) {
     2     if (index > size || index < 0)
     3         throw new IndexOutOfBoundsException(
     4         "Index: "+index+", Size: "+size);
     5 
     6     ensureCapacity(size+1);  // Increments modCount!!
     7     System.arraycopy(elementData, index, elementData, index + 1,
     8              size - index);
     9     elementData[index] = element;
    10     size++;
    11     }
    复制代码

    1、第6行的扩容部分后面再解释,其余的比较简单,我们直接看第7行。调用的是System.arraycopy的方法。

    2、第一次看到这个方法有点搞不懂,先来解释下:System.arraycopy(src, srcPos, dest, destPos, length);

         第一个参数表示的是要被复制的数组;第二个参数表示数组中从第几个元素开始复制。

         第三个参数表示复制到哪个数组;第四个参数表示复制到那个数组从哪个元素开始;第五个参数表示要复制的长度

    3、解释完这个方法就很清楚了,add方法就是将数组中待添加元素的位置后面所有的元素(包括该位置),通过copy的复制方法,全部后移一个位置。然后将待添加的元素放到指      定的位置上。当然这个数组可能是原数组,也可能是经过第6行代码扩容之后新的数组。

    扩容

    扩容,动态扩容,也就是前面所提到的ArrayList的底层是由一个动态变化的数组实现的。

    复制代码
     1 public void ensureCapacity(int minCapacity) {
     2     modCount++;
     3     int oldCapacity = elementData.length;
     4     if (minCapacity > oldCapacity) {
     5         Object oldData[] = elementData;
     6         int newCapacity = (oldCapacity * 3)/2 + 1;
     7             if (newCapacity < minCapacity)
     8         newCapacity = minCapacity;
     9             // minCapacity is usually close to size, so this is a win:
    10             elementData = Arrays.copyOf(elementData, newCapacity);
    11     }
    12     }
    复制代码

    1、我们看扩容的算法,也就是在旧容量的基础上,扩大1.5倍再加上1。至于为什么是这样一个算法,我也没明白。但是JDK开发人员肯定是在这方面做过思考的:不能一次性扩容太大,会造成内存空间的浪费;也不能扩容得不够,否则下一次扩容的操作会很快到来。我猜想应该是基于这样的考虑才设计了这样一个算法。

    2、扩容结束后,就是将旧数组里面的元素全部复制到新的数组里。并且新数组还是通过elementData变量来引用。

     remove方法解读

    我们先来看下该方法的源码:

    复制代码
     1  public E remove(int index) {
     2     RangeCheck(index);
     3 
     4     modCount++;
     5     E oldValue = (E) elementData[index];
     6 
     7     int numMoved = size - index - 1;
     8     if (numMoved > 0)
     9         System.arraycopy(elementData, index+1, elementData, index,
    10                  numMoved);
    11     elementData[--size] = null; // Let gc do its work
    12 
    13     return oldValue;
    14     }
    复制代码

    其实这个remove的方法处理的过程也比较简单:

    1、第2行代码是用来检测数组下标是否越界。

    2、然后取出该位置上的数组元素。

    3、通过arryCopy方法将待删除元素之后的所有元素往前一个位置复制。(注意,这个动作是先复制,然后粘贴)。

    4、这个时候最后一个位置上的元素就是多余的,所以才有了第11行的处理,将其置为null。

    ArrayList的优缺点

    1、底层是由数组实现的,便于随机访问。

    2、顺序添加元素性能比较高,相当于每次在数组最后添加一个元素、

    3、插入元素、删除元素的时候,会涉及到元素的复制,即调用arrayCopy方法,如果复制的元素比较多,则这样就比较消耗性能。

    总结来说:ArrayList的优势是随机访问、顺序添加。

  • 相关阅读:
    换肤动画
    手风琴动画图
    Ajax传值原理.aspx文档
    三层框架中单表的增删改查
    用ajax传JSON数据
    利用ajax进行post传值,登录QQ和密码代码
    ado.net增删改查及存储过程
    常用的SQL语句
    金融
    写你的简历应该注意什么
  • 原文地址:https://www.cnblogs.com/yechanglv/p/6931048.html
Copyright © 2011-2022 走看看