Java----- ArrayList构造、add、remove、clear方法实现原理源码分析

一.ArrayList内部的实现方式

ArrayList内部是通过Object[]实现的。


二.源码分析:

(1).构造方法

    public ArrayList() {
        array = EmptyArray.OBJECT;
    }

    public ArrayList(int capacity) {
        if (capacity < 0) {
            throw new IllegalArgumentException("capacity < 0: " + capacity);
        }
        array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]);
    }

    public ArrayList(Collection<? extends E> collection) {
        if (collection == null) {
            throw new NullPointerException("collection == null");
        }
        Object[] a = collection.toArray();
        if (a.getClass() != Object[].class) {
            Object[] newArray = new Object[a.length];
            System.arraycopy(a, 0, newArray, 0, a.length);
            a = newArray;
        }
        array = a;
        size = a.length;
    }
ArrayList有3个构造方法, 先看第一个,array是一个成员变量,它是Object[]类型的,当我们在new一个空参的ArrayList的时候,系统默认调用了EmptyArray中的OBJECT属性,EmptyArray类具体实现如下:
public final class EmptyArray {
    private EmptyArray() {}

    public static final boolean[] BOOLEAN = new boolean[0];
    public static final byte[] BYTE = new byte[0];
    public static final char[] CHAR = new char[0];
    public static final double[] DOUBLE = new double[0];
    public static final int[] INT = new int[0];

    public static final Class<?>[] CLASS = new Class[0];
    public static final Object[] OBJECT = new Object[0];
    public static final String[] STRING = new String[0];
    public static final Throwable[] THROWABLE = new Throwable[0];
    public static final StackTraceElement[] STACK_TRACE_ELEMENT = new StackTraceElement[0];
    public static final java.lang.reflect.Type[] TYPE = new java.lang.reflect.Type[0];
    public static final java.lang.reflect.TypeVariable[] TYPE_VARIABLE =
        new java.lang.reflect.TypeVariable[0];
}
从EmptyArray类中可知,当默认使用ArrayList空参的构造方法的时候,ArrayList内部会new Object[0]的空数组。 再看ArrayList的第二个构造方法,先检验参数的有效性,当传入的参数小于0的时候,会抛出非法参数异常。如果参数合法,成员变量array的赋值,使用的是一个三元运算,当capacity == 0时,系统默认生成一个空数组,当capacity>0时,系统会生成一个长度为capacity的数组。 最后看第三个构造方法,第一步对输入参数的合法性检验,若为空,则抛出空指针异常;第二步将输入集合转换成数组a;第三步判断当前数组a是否是Object[]类型,如果不是,创建一个Object类型的数组进行复制( 复制方法使用System.arraycopy),再赋值给a;第四步将转换的数组a赋值给成员变量array;第五步将数组的长度赋值给成员变量size。


(2).add()方法

 /**
     * Adds the specified object at the end of this {@code ArrayList}.
     *
     * @param object
     *            the object to add.
     * @return always true
     */
    @Override public boolean add(E object) {
        Object[] a = array;
        int s = size;
        if (s == a.length) {
            Object[] newArray = new Object[s +
                    (s < (MIN_CAPACITY_INCREMENT / 2) ?
                     MIN_CAPACITY_INCREMENT : s >> 1)];
            System.arraycopy(a, 0, newArray, 0, s);
            array = a = newArray;
        }
        a[s] = object;
        size = s + 1;
        modCount++;
        return true;
    }
这里只分析简单的add()方法,第一步将数组,集合长度赋值给局部变量a和s;第二步判断集合的长度是否等于数组的长度,如果等于,需要重新分配数组和重新计算分配内存的空间大小。源码计算内存空间的大小,使用的是一个三元表达式,当集合的长度小于 MIN_CAPACITY_INCREMENT/2 时,系统会分配MIN_CAPACITY_INCREMENT各长度;当集合的长度大于 MIN_CAPACITY_INCREMENT/2 时,系统会分配当前长度的一半(s >>1表示当前长度右移一位,相当于s = s/2)。然后将数组的数据赋值到新的数组中,再更新原来数组。
private static final int MIN_CAPACITY_INCREMENT = 12;
第三步将传入的Object对象添加到数组下标为s处;第四步将当前集合长度加1;第五步modCount自增,它主要是用来记录集合修改的次数( 判断是否出现并发修改异常)。

(3).remove()方法

/**
     * Removes the object at the specified location from this list.
     *
     * @param index
     *            the index of the object to remove.
     * @return the removed object.
     * @throws IndexOutOfBoundsException
     *             when {@code location < 0 || location >= size()}
     */
    @Override public E remove(int index) {
        /**
       * 1.局部变量赋值
       */
        Object[] a = array;
        int s = size;
	/**
	 * 2.判断删除的下标是否超过了集合的长度,超过抛出越界异常
	 */
        if (index >= s) {
            throwIndexOutOfBoundsException(index, s);
        }
	 /**
	  * 3.获取下标index的所对应的元素
	  */
        @SuppressWarnings("unchecked") 
	  E result = (E) a[index];
	 /**
	 * 4.将下标index后面的所有元素都向前移动一位
	 */
        System.arraycopy(a, index + 1, a, index, --s - index);
	 /**
	 * 5.集合最后一位设置为空,防止内存泄露,因为删除了一个元素
	 */
        a[s] = null;  // Prevent memory leak
        /**
       * 6.集合长度重新赋值
       */
        size = s;
	/**
	 * 7.记录修改次数
	 */
        modCount++;
        return result;
    }

(4).clear()方法

    /**
     * Removes all elements from this {@code ArrayList}, leaving it empty.
     *
     * @see #isEmpty
     * @see #size
     */
    @Override public void clear() {
        /**
       * 判断集合大小是否不等于0
       */
        if (size != 0) {
	     /**
	     * 将数组的数据元素填充为null
	     */
            Arrays.fill(array, 0, size, null);
	     /**
	     * 集合长度设置为0
	     */
            size = 0;
	     /**
	     * 记录修改次数
	     */
            modCount++;
        }
    }











  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值