ArrayList 源码分析 (相差无几的1.7和1.8)

      ArrayList是Java容器中相对比较简单的一个,它底层是采用数组实现的,包括的主要操作有remove 、set、contains、clear、add、clone、indexOf、toString等等常用的方法,下面来简单分析一下这些方法的实现,有些实在是比较简单的就不写了。

ArrayList重要参数及构造方法

   /**
     * 默认容量为10
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 空集合
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 存放元素的数组
     */
    private transient Object[] elementData;

    /**
     * ArrayList的大小.
     *
     * @serial
     */
    private int size;

    /**
     * 使用传入的参数构造一个数组.
     *
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
    }

    /**
     * 构造一个空列表,初始化为10 .
     */
    public ArrayList() {
        super();
        this.elementData = EMPTY_ELEMENTDATA;
    }

    /**
     *  使用一个集合来给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);
    }

ArrayList比较重要的而方法。

 扩容方法。底层采用array.copyOf 和System.arraycopy来实现数组的复制,同时扩容机制采用每次乘以原来的1.5倍进行扩容。

 /**
     * 
     *如果传入的最小容量要比当前最小容量要大,那么就扩容
     * @param   minCapacity   the desired minimum capacity
     */
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != EMPTY_ELEMENTDATA)//获取当前最小容量0 或者是10
            // any size if real element table
            ? 0
            // larger than default for empty table. It's already supposed to be
            // at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {//有需要就扩容
            ensureExplicitCapacity(minCapacity);
        }
    }

    private void ensureCapacityInternal(int minCapacity) {//数组为空,设置相应容量
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;//修改数加一,避免并发出错

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

    /**
     *  最大数组大小
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * 
     *1.5倍扩容,不行就把数组变成最大。
     * @param minCapacity the desired minimum capacity
     */
    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:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

插入

 /**
* 在指定的位置插入值,index必须小于等于size
*/ 
public void add(int index, E element)
 { 
    rangeCheckForAdd(index); 
   ensureCapacityInternal(size + 1);
 // 看看要不要扩容 
    System.arraycopy(elementData, index, 
    elementData, index + 1, size - 
     index);
//采用复制的方式 
 elementData[index] = element; size++; }
 
 查找元素(根据下标和元素)
 /**
     * 返回第一次出现这个元素的索引,找不到就返回-1,还有一个lastIndexOf,查找最后一个,差不多
     */
    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;
    }


删除

/**
     *根据索引来删除元素
     */
    public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);//原数组,起始位置,目标数组,起始位置,复制个数
        elementData[--size] = null;

        return oldValue;
    }

    /**
     * 使用fastremove来删除,值时不返回值而已。
     */
    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;
    }

      除了上述简单方法之外,ArrayList中还有三个比较有意思的内部类,分别是实现了Iterator和ListIterator的两个内部类以及一个实现随机存取的SubList类,但是无论是迭代器也好随机存取也好,其内部实现和上面的方法都比较类似,区别可能比较大的地方在与迭代器中都有modCount的计数器,每次比较全局计数器和自己现成的计数器是不是有区别,有的话产生fast-fail机制并抛出ConcurrentModifactionException,也就是多线程下有线程在别的线程使用迭代器修改了一些东西,就会抛出异常防止越界等问题的出现。

       再就是1.8和1.7的区别,由于都是比较简单的数组实现,可能除了1.8的代码写的更好之外,再就是1.8的代码行数比较多之外(1.8 1461行 1.7 1173行),也可能是注释写的比较详细。其主要函数的具体实现相差无几,这里就不在赘述了。





  查看的博客:https://juejin.im/post/5adfe654f265da0b7f443477

                       https://blog.csdn.net/u012883858/article/details/51393055

                      https://juejin.im/post/5a45b3f05188257d1718d386#heading-2

猜你喜欢

转载自blog.csdn.net/pb_yan/article/details/80231337