ArrayList源码分析(基于JDK1.8)

Posted qqailove

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ArrayList源码分析(基于JDK1.8)相关的知识,希望对你有一定的参考价值。

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable

    从ArrayList<E>可以看出它是支持泛型的,它继承自AbstractList,实现了List、RandomAccess、Cloneable、java.io.Serializable接口。

    AbstractList提供了List接口的默认实现(个别方法为抽象方法)。

    List接口定义了列表必须实现的方法。

    RandomAccess是一个标记接口,接口内没有定义任何内容。

    实现了Cloneable接口的类,可以调用Object.clone方法返回该对象的浅拷贝。

    通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。序列化接口没有方法或字段,仅用于标识可序列化的语义。

 

ArrayList几个重要的字段属性

    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};   
   // 存储ArrayList的元素
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    // elementData指示elementData包含的元素的数量
    private int size;

    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 = {};
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    // 使用集合来初始化
    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;
        }
    }

第一个构造方法:根据指定容量进行构造elementData数组。

第二个无参构造方法:初始化为{},size也为0.当执行add操作的时候,如果为{},则将其容量初始化为DEFAULT_CAPACITY,即为10

第三个构造方法:将集合对象转换成Object数组。Arrays的方法在另一篇博文将做分析。

 

其它方法:

add(E e):

    public boolean add(E e) {
        // 扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
     // 如果elementData为空,则初始化为DEFAULT_CAPACITY
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; }
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code , 如果扩容大于elementData容量,进行扩容。
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        // newCapacity = oldCapacity * 1.5  扩大为之前的1.5倍。
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            // 如果扩容后,newCapacity还是小于minCapacity,则直接赋值为minCapacity
            newCapacity = minCapacity;
     // 如果1.5 * elementData.length比Integer.MAX_VALUE - 8还大
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); }
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
     // 如果minCapacity即为Array.length大于Integer.MAX_VALUE - 8. 则直接赋为Integer.MAX_VALUE , 否则就为MAX_ArraySIZE
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }

 

为什么是1.5倍扩容呢?

 

public boolean addAll(Collection<? extends E> c)

先将集合c转换成数组,根据转换后数组的程度和ArrayList的size拓展容量,之后调用System.arraycopy方法复制元素到elementData的尾部,调整size。根据返回的内容分析,只要集合c的大小不为空,即转换后的数组长度不为0则返回true。

public boolean addAll(int index, Collection<? extends E> c) 

先判断index是否越界。其他内容与addAll(Collection<? extends E> c)基本一致,只是复制的时候先将index开始的元素向后移动X(c转为数组后的长度)个位置(也是一个复制的过程),之后将数组内容复制到elementData的index位置至index+X。

 

clear的时候并没有修改elementData的长度(好不容易申请、拓展来的,凭什么释放,留着搞不好还有用呢。这使得确定不再修改list内容之后最好调用trimToSize来释放掉一些空间),只是将所有元素置为null,size设置为0。

    public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }

 

返回此 ArrayList 实例的浅表副本。(不复制这些元素本身。),如果是对象,只是复制引用。

    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn‘t happen, since we are Cloneable
            throw new InternalError(e);
        }
    }

 

indexOf:通过遍历elementData数组来判断对象是否在list中,若存在,返回元素下标的位置。时间复杂度是O(n)

    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;
    }

 

lastIndexOf:从后向前遍历。

 

remove:

    public E remove(int index) {
        rangeCheck(index);

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

        int numMoved = size - index - 1;
        if (numMoved > 0)
            // 从index+1开始的元素复制到elementData中从index下标开始,总共有numMoved个元素。
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

 

    public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                // fastRemove基本和remove的代码一致,只是不用进行边界判断。
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

 

以上是关于ArrayList源码分析(基于JDK1.8)的主要内容,如果未能解决你的问题,请参考以下文章

ArrayList的源码分析(基于jdk1.8)

Java集合基于JDK1.8的ArrayList源码分析

ArrayList源码分析--jdk1.8

深入ArrayList源码分析(JDK1.8)

AQS源码分析--jdk1.8

ArrayList源码阅读分析(JDK1.8)