• ArrayList源码分析


    对于ArrayList,顾名思义,称之为数组列表。要明白,它的底层结构是数组,也就是说,ArrayList存储的元素其实是放在了它内部的一个数组中,对ArrayList的操作,其实就是对它内部这个数组的操作。接下来,我们从它的属性,构造器,方法三个方面来分析源码。

    1.ArrayList的属性

         /**
         * Default initial capacity.
         */
    //默认的初始容量 private static final int DEFAULT_CAPACITY = 10; /** * Shared empty array instance used for empty instances. */
    //一个空数组,当创建无参ArrayList时,底层数组默认的就是这个 private static final Object[] EMPTY_ELEMENTDATA = {}; /** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. Any * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to * DEFAULT_CAPACITY when the first element is added. */
    //存放元素的底层数组,此数组的长度也就是数组列表的容量 private transient Object[] elementData; /** * The size of the ArrayList (the number of elements it contains). * * @serial */
    //ArrayList的大小,也就是它存储元素的个数
    private int size;

    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
         */
    //构造一个ArrayList,并指定初始容量initialCapacity public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; } /** * Constructs an empty list with an initial capacity of ten. */
    //构造一个ArrayList,它初始容量是默认的,为10 public ArrayList() { super(); this.elementData = EMPTY_ELEMENTDATA; } /** * 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 */
    //构造一个ArrayList,并将指定的集合中的元素放到这个数组列表中 public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); size = elementData.length; // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); }

    3.方法

    add(E e) :将指定的元素添加到列表的尾部

    add方法的逻辑如下:

    (1).保证数组长度大于等于数组中的现有元素个数+1,这样才能添加下一个元素

    (2).然后将修改次数+1,如果不能满足(1)中的条件,那么就需要进行扩容,创建一个新数组,其长度是原来数组的1.5倍,同时把原来数组中的元素都拷贝到新数组中。

    public boolean add(E e) {
    //确保ArrayList容量大于等于现有的元素个数+1 ensureCapacityInternal(size
    + 1); // Increments modCount!!
    //将元素添加到数组的尾部 elementData[size++] = e; return true; }
     private void ensureCapacityInternal(int minCapacity) {
    //获取期望得到的ArrayList容量
    if (elementData == EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); }
      private void ensureExplicitCapacity(int minCapacity) {
            modCount++; //修改次数+1
    
            // overflow-conscious code
    //如果期望的到的ArrayList容量大现在的ArrayList容量,那么就扩容,就是创建一个长度更大的数组,然后将原来数组中的元素拷贝到新数组中,这个新数组作为ArrayList的底层数组
    //需要理解的是:ArrayList的容量也就是它底层数组的长度,ArrayList的大小size是指它存储元素的个数;这两个概念要清楚 if (minCapacity - elementData.length > 0)
           //扩容操作   grow(minCapacity); }
     private void grow(int minCapacity) {
            // overflow-conscious code
            int oldCapacity = elementData.length;
            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:
    //将原来数组中的元素拷贝到新数组中,新数组的长度是newCapacity elementData = Arrays.copyOf(elementData, newCapacity); }

    add(int index,E element) : 将指定元素插入到此列表中的指定位置

    由这个方法,我们可以明白对于ArrayList,插入的效率比较低的原因,因为从index位置开始的元素都整体往后一个单位进行拷贝。同理,删除操作效率较低也是类似的原因。

     public void add(int index, E element) {
    //检查index,是否越界 rangeCheckForAdd(index); //确保数组长度够用 ensureCapacityInternal(size
    + 1); // Increments modCount!!
    //通过copy的方式,从下标位置是index开始到最后一个元素,整体后移1个单位 System.arraycopy(elementData, index, elementData, index + 1, size - index);
    //把指定元素插入index位置 elementData[index]
    = element; size++; }

    remove(int index):移除此列表中指定位置的元素

      public E remove(int index) {
    //检查是否越界 rangeCheck(index); //修改次数+1 modCount
    ++;
    //指定位置的元素 E oldValue
    = elementData(index); //要移动的元素个数 int numMoved = size - index - 1; if (numMoved > 0)
    //通过copy的方式,将index+1位置开始的元素整体向前移动一个单位(其实是拷贝) System.arraycopy(elementData, index
    +1, elementData, index, numMoved);
    //将最后一个元素位置的值设置为null,然后元素个数-1 elementData[
    --size] = null; // clear to let GC do its work return oldValue; }

    set(int index,E element):将指定元素替换此列表中指定位置的元素

     public E set(int index, E element) {
            rangeCheck(index);
            //获取指定位置的元素,被替换后,并返回
            E oldValue = elementData(index);
            elementData[index] = element;
            return oldValue;
        }

     remove(Object o):移除此列表中首次出现的元素

     public boolean remove(Object o) {
            if (o == null) {
                for (int index = 0; index < size; index++)
                    if (elementData[index] == null) {
                        fastRemove(index);
                        return true;
                    }
            } else {
                for (int index = 0; index < size; index++)
    //找到指定元素的下标位置
    if (o.equals(elementData[index])) {
    //移除操作 fastRemove(index);
    return true; } } return false; }
     private void fastRemove(int index) {
    //修改次数+1 modCount
    ++;
    //需要移动的元素的数量
    int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved);
    elementData[
    --size] = null; // clear to let GC do its work }

    addAll(int index,Collection<? extends E> c):从指定的位置开始,将collection中的元素插入到此列表中

        public boolean addAll(int index, Collection<? extends E> c) {
            //判断index是否越界
    rangeCheckForAdd(index); Object[] a
    = c.toArray(); int numNew = a.length;
    //确保数组长度够用,不够就扩容 ensureCapacityInternal(size
    + numNew); // Increments modCount //经过以下两次copy操作就可以把collection中的元素全部插入到列表中 int numMoved = size - index; if (numMoved > 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); System.arraycopy(a, 0, elementData, index, numNew); size += numNew; return numNew != 0; }

    总结:ArrayList的特点是查询效率高,增加和删除效率低,因为它的底层结构是数组。此外,它不是线程安全的。

  • 相关阅读:
    Eclipse详细设置护眼背景色和字体颜色并导出
    详解equals()方法和hashCode()方法
    MFC+WinPcap编写一个嗅探器之七(协议)
    fastjson使用
    2017-04-07 开通博客
    开启mysql慢查询
    MYSQL介绍安装及一些问题解决
    python基础入门
    Linux重启与关机命令
    Scanner类与Random类
  • 原文地址:https://www.cnblogs.com/51life/p/9269414.html
Copyright © 2020-2023  润新知