ArrayList源码分析(jdk11)

参数:

    private static final int DEFAULT_CAPACITY = 10;//默认初始容量
    
     /**
     * 用户指定容量为0时返回数组
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};
    
     /**
     * 用户调用无参构造函数,在第一次添加元素时会以DEFAULT_CAPACITY扩容
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 保存数据,数组大小是arraylist的容量
     * transient:表示对象序列化时不包括该数组(writeObject()和readObject()实现对数组序列化和反序列化)
     * 原因:elementData是一个缓存数组,它通常会预留一些容量,等容量不足时再扩充容量,
     * 那么有些空间可能就没有实际存储元素,采用上诉的方式来实现序列化时,
     * 就可以保证只序列化实际存储的那些元素,而不是整个数组,从而节省空间和时间。
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * arraylist中实际大小(保存数据数量)
     */
    private int size;  
    
    /**
     * 可以分配数组的最大值
     * OutOfMemoryError: 申请数组大小超过vm限制
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

构造方法:

    //创建指定初始容量的空arraylist
    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);
        }
    }


    //无参构造函数,在第一次加入元素时扩容至默认容量
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    // 创建一个包含collection的ArrayList
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();//将集合转为数组
        if ((size = elementData.length) != 0) {//将数组长度赋值给size 并判断是否为0       
            if (elementData.getClass() != Object[].class)//如果数组不是objec[]t类型
                elementData = Arrays.copyOf(elementData, size, Object[].class);//将数组拷贝到object[]数组
        } else {
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

扩容方法:

 /**  
     * 扩展ArrayList容量(提供给使用者的方法) :为了确保数组容量大于minCapacity
     * 作用:在 add 大量元素之前调用,以避免多次扩容
     */
    public void ensureCapacity(int minCapacity) {
        if (minCapacity > elementData.length
            && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
                 && minCapacity <= DEFAULT_CAPACITY)) {
            modCount++;
            grow(minCapacity);
        }
    }


    /**
    * 数组扩容,当size等于数组长度并加入新数据时调用
    */
    private Object[] grow() {
        return grow(size + 1);
    }
    
    /**
     *数组扩容
     * @param minCapacity 指定最小容量
     * @throws OutOfMemoryError 最小容量小于0抛出异常
     */
    private Object[] grow(int minCapacity) {
        return elementData = Arrays.copyOf(elementData,
                                           newCapacity(minCapacity));//创建新数组,复制数据
    }



    /**
     * 返回扩容后的数组容量(1.5*oldCapacity)
     */
    private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;//数组原有的长度
        int newCapacity = oldCapacity + (oldCapacity >> 1);//扩容后的长度,1.5*oldCapacity
        if (newCapacity - minCapacity <= 0) {
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)//如果当前数组为空
                return Math.max(DEFAULT_CAPACITY, minCapacity);//返回指定容量和默认容量的最大值
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return minCapacity;
        }
        return (newCapacity - MAX_ARRAY_SIZE <= 0)? newCapacity :hugeCapacity(minCapacity);
    }
    
    /**
     * 当newCapacity超过MAX_ARRAY_SIZE时,调用此函数
     */
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE)
            ? Integer.MAX_VALUE
            : MAX_ARRAY_SIZE;
    }

查找元素索引:

     /**
     *判断元素在arraylist中的索引,不存在返回-1
     */
    public int indexOf(Object o) {
        return indexOfRange(o, 0, size);
    }
     /**
     *判断元素在arraylist某一范围内的索引,不存在返回-1
     */
    int indexOfRange(Object o, int start, int end) {
        Object[] es = elementData;
        if (o == null) {
            for (int i = start; i < end; i++) {
                if (es[i] == null) {
                    return i;
                }
            }
        } else {
            for (int i = start; i < end; i++) {
                if (o.equals(es[i])) {
                    return i;
                }
            }
        }
        return -1;
    }
     /**
     *查找元素在arraylist中的最后出现的索引,不存在返回-1
     */
   public int lastIndexOf(Object o) {
        return lastIndexOfRange(o, 0, size);
    }
     /**
     *查找元素在arraylist中某一范围内最后出现的索引,不存在返回-1
     */
    int lastIndexOfRange(Object o, int start, int end) {
        Object[] es = elementData;
        if (o == null) {
            for (int i = end - 1; i >= start; i--) {//从数组末尾开始遍历
                if (es[i] == null) {
                    return i;
                }
            }
        } else {
            for (int i = end - 1; i >= start; i--) {
                if (o.equals(es[i])) {
                    return i;
                }
            }
        }
        return -1;
    }

加入数据:

    /**
     * 
     */
   //向当前数组末尾加入元素
   public boolean add(E e) {
        modCount++;
        add(e, elementData, size);
        return true;
    }
   //判断size与当前数组大小,如果相等则扩容数组
    private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)
            elementData = grow();
        elementData[s] = e;
        size = s + 1;
    }
    
    //向指定位置加入元素
    public void add(int index, E element) {
        //判断下标是否越界
        rangeCheckForAdd(index);
        modCount++;
        final int s;
        Object[] elementData;
        if ((s = size) == (elementData = this.elementData).length)
            elementData = grow();           
        //index后的元素向后移动一位       
        System.arraycopy(elementData, index,
                         elementData, index + 1,
                         s - index);
        elementData[index] = element;
        size = s + 1;
    }
   //判断下标与size的大小
  private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

总结:
1.如果调用无参构造函数,先调用grow()扩容,扩容大小为默认容量
2.如果调用有参构造函数,如果当前size达到容量,先调用grow()扩容

注意:下面的代码第三行会报错java.lang.IndexOutOfBoundsException
在创建ArrayList对象时指定了初始容量5.

a.add(0,1):size=0,index=0, rangeCheckForAdd(int index)检查index与size的大小,执行成功

a.add(2,1):size=1, index=2,index>size,rangeCheckForAdd方法抛出异常

      ArrayList<Integer> a = new ArrayList<>(5);
      a.add(0,1);
      a.add(2,1);

所以虽然在构造方法中指定了初始容量,仍然不能访问数组中size大小以后的位置。

System.arraycopy()与Arrays.copyOf():

Arrays.copyOf():调用了System.arraycopy()方法,参数为源数组和复制长度,方法自动创建目标数组,将源数组全部元素复制到目标数组并返回目标数组。

public static int[] copyOf(int[] original, int newLength) {
        int[] copy = new int[newLength];
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }

System.arraycopy():native方法,需要指定源数组、目标数组、起始索引和复制长度

public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值