ArrayList源码阅读

    // 序列化ID
    private static final long serialVersionUID = 8683452581122892189L;

    // 默认初始化容量
    private static final int DEFAULT_CAPACITY = 10;

    // 空数组
    private static final Object[] EMPTY_ELEMENTDATA = {};

    // 空数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    //存储ArrayList元素的数组缓冲区。ArrayList的容量是该数组缓冲区的长度
    transient Object[] elementData; // non-private to simplify nested class access

    // 当前arraylist集合的大小,也就是elementData数组中数据元素的个数
    private int size;



    /**
     * 形式一:携带一个int类型的参数,指定arraylist的初始容量
     * 
     * initialCapacity为我们所指定的数组列表初始容量,
     * 方法中对参数:initialCapacity的值进行了一系列判断,
     * 当参数:initialCapacity的初始容量小于0时无意义,直接抛出非法参数异常。
     * 当参数:initialCapacity大于0时,会直接创建一个Object类型的数组,数组的初始大小就是initialCapacity的值。
     * 当initialCapacity等于0时,会直接将elementData指向EMPTY_ELEMENTDATA空数组。
     * 
     */
    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);
        }
    }

    /**
     * 形式二:无参构造方法
     * 在构造方法中直接将 elementData 指向 DEFAULTCAPACITY_EMPTY_ELEMENTDATA空数组,
     * 该ArrayList的size为初始值0。
     */

    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

     /**
     * 形式三:携带一个Collection类型的参数
     * 代码中首先将集合参数通过toArray方法转换成数组,并赋值给elementData,
     * 然后对arraylist中的size进行赋值并判断size是否等于0.
     * 当大小为0时,直接将elementData指向EMPTY_ELEMENTDATA空数组。
     * 当size不为0时执行copyOf方法。
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
    add()方法


    /**
     * 方式一:直接添加数据元素到arraylist的尾部
     * 方法中首先调用到ensureCapacityInternal方法,将size+1作为参数传入。
     * size用来表示当前数组列表的大小,也就是elementData中数组中元素的个数,
     * 大小size+1就是确保数据元素添加成功的最小容量.
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }


    /**
     * calculateCapacity方法中首先将elementData 和DEFAULTCAPACITY_EMPTY_ELEMENTDATA进行对比,
     * 如果elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA,则执行 if 语句体的操作,
     * 否则直接调用ensureExplicitCapacity方法,将最小容量minCapacity作为参数传入。
     * 当我们通过ArrayList的无参构造方法创建ArrayList对象时,
     * 在构造方法中会直接将elementData指向DEFAULTCAPACITY_EMPTY_ELEMENTDATA。
     * 当我们通过ArrayList的无参构造方法创建ArrayList对象后,再调用add方法的时候会执行if语句体操作,
     * 将minCapacity 重新赋值为DEFAULT_CAPACITY和minCapacity中的最大值。   
     */
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }


    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }




    /**
     * 方法中首先将变量modCount自增1,
     * modCount是用来标记当前arraylist集合操作变化的次数,在fail-fast机制中会有用到这个变量.
     * 接着判断minCapacity - elementData.length 是否大于0,
     * 当minCapacity - elementData.length大于0的时候说明当前elementData数组大小不够使用,
     * 需要扩容,grow方法就是具体的扩容操作
     */
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }


     private void grow(int minCapacity) {
    	// 1.首先获取到elementData数组的长度,作为原容量
        int oldCapacity = elementData.length;
        // 2.新容量 = 原容量 + 原容量/2;   1.5倍扩容
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
        	// 3.若1.5倍扩容后还不够,则将最小容量作为新容量
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
        	 // 4.限制最大容量
            newCapacity = hugeCapacity(minCapacity);
        // 5.进行原有数据元素copy处理
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
remove()函数


     /*
     * 方式一:根据角标进行remove操作
     */
    public E remove(int index) {
    	// 1. 对角标越界进行判断
        rangeCheck(index); 
        // 2.modCount自增1
        modCount++;
        // 3.获取到指定下角标位置的数据
        E oldValue = elementData(index);
        // 4.计算需要移动的元素个数
        int numMoved = size - index - 1;
        if (numMoved > 0)
        	// 5. 指定角标位置后的元素前移一位
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        // 6.将size自减1,并将数组末尾置为null,便于垃圾回收
        elementData[--size] = null; // clear to let GC do its work
        // 7.最后将所要删除的数据元素return掉
        return oldValue;
    }


    /*
     * 方式二:根据数据元素进行remove操作
     * 方法中首先对当前remove的数据元素进行null判断。
     * 无论当前remove的数据元素是否为null,都需要一个for循环进行遍历操作,
     * 注意if条件块的代码在数据元素为null和不为null两种情况下是不同的。
     * 如果elementData数组中某一角标处的元素等于当前remove的数据元素,
     * 会调用fastRemove方法进行具体remove操作,最后return true表示remove操作成功。
     * 否则return false表示remove操作失败。
     */
    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的值自增1
        modCount++;
        // 2.计算需要移动的元素个数
        int numMoved = size - index - 1;
        // 3. 指定角标位置后的元素前移一位
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        // 4.将size自减1,并将数组末尾置为null,便于垃圾回收
        elementData[--size] = null; // clear to let GC do its work
    }
set()函数
  
  /**
     * set方法需要接受两个参数,第一个参数index为下角标,第二个参数element为数据元素,
     * 表示将下角标index处的数据元素赋值为element。在方法中,首先对index下角标进行越界判断,
     * 然后获取到角标index处的原数据元素oldValue,
     * 接着将角标index处的数据元素赋值为element,最后将原有数据元素oldValue return掉。
     */
    public E set(int index, E element) {
    	//对index进行越界检查
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }
    get()函数

    public E get(int index) {
    	//对index进行越界检查
        rangeCheck(index);
        //返回数据
        return elementData(index);
    }
    clear()函数

    public void clear() {
        //对modCount自增
        modCount++;

        // 遍历操作,将elementData数组角标元素置为null。
        for (int i = 0; i < size; i++)
            elementData[i] = null;
        //将数组size设置为0
        size = 0;
    }
contains()函数

    /*
     * indexOf方法是将一个数据元素传入,返回该数据元素对应的下角标,
     * 如果数据元素在当前arraylist中不存在,则返回-1。
     * 也就是说当数据元素在当前arraylist中存在时,indexOf(o) >= 0成立,结果为true,
     * 否则为false。
     */
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }


     /**
     * indexOf方法中对数据元素进行了null判断,两种情况下都进行了遍历操作,
     * 两种情况下的if条件语句不同。
     * 当满足条件时,直接将对应的下角标return掉,否则return -1,
     * 表示当前arraylist中不存在该元素
     */
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值