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

来源:互联网 发布:php 监控 插件 编辑:程序博客网 时间:2024/06/05 03:07

一.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 0
原创粉丝点击