Collection framework ArrayList source code analysis (two)

Arraylist introduction

ArrayList data structure

ArrayList source code analysis

ArrayList traversal method

toArray() exception

Part 1: Introduction to Arraylist

  • Introduction to ArrayList

ArrayList is an array queue, and the data structure used at the bottom layer is an array, which is equivalent to a dynamic array. Compared with the array in Java, its capacity can be dynamically expanded. It inherits from AbstractList and implements interfaces such as List, RandomAccess, Cloneable, and java.io.Serializable.

ArrayList  inherits AbstractList and implements List . It is an array queue that provides related functions such as adding, deleting, modifying, and traversing.

ArrayList  implements the RandmoAccess interface, which provides random access functions. RandmoAccess is used in Java to be implemented by List and provides quick access to List. In ArrayList, we can quickly get the element object by the number of the element; this is fast random access. Later, we will compare the efficiency of List's "Fast Random Access" and "Access via Iterator".

ArrayList implements the Cloneable interface, that is, it covers the function clone() and can be cloned. Because you want to use the clone() method of Object, you must implement the Cloneable interface.

ArrayList implements the java.io.Serializable interface, which means that ArrayList supports serialization and can be transmitted through serialization.

ArrayList is different from Vector. Operations in Arraylist are not thread-safe! Of course, thread insecurity will only appear for multi-threading, so it is recommended to use Arraylist in single-threaded situations. If it is used in multi-threaded situations, the thread safety of ArrayList must be ensured in the business. You can use Vector and CopyWriteArrayList in multi-threaded situations, and I will explain why you should use Vector or CopyWriteArrayList in multi-threaded situations.

  • Constructor of ArrayList:
// 默认构造函数
ArrayList()

// capacity是ArrayList的默认容量大小。当由于增加数据导致容量不足时,容量会添加上一次容量大小的一半。
ArrayList(int capacity)

// 创建一个包含collection的ArrayList
ArrayList(Collection<? extends E> collection)
  • ArrayList的API
// Collection中定义的API
boolean             add(E object)
boolean             addAll(Collection<? extends E> collection)
void                clear()
boolean             contains(Object object)
boolean             containsAll(Collection<?> collection)
boolean             equals(Object object)
int                 hashCode()
boolean             isEmpty()
Iterator<E>         iterator()
boolean             remove(Object object)
boolean             removeAll(Collection<?> collection)
boolean             retainAll(Collection<?> collection)
int                 size()
<T> T[]             toArray(T[] array)
Object[]            toArray()
// AbstractCollection中定义的API
void                add(int location, E object)
boolean             addAll(int location, Collection<? extends E> collection)
E                   get(int location)
int                 indexOf(Object object)
int                 lastIndexOf(Object object)
ListIterator<E>     listIterator(int location)
ListIterator<E>     listIterator()
E                   remove(int location)
E                   set(int location, E object)
List<E>             subList(int start, int end)
// ArrayList新增的API
Object               clone()
void                 ensureCapacity(int minimumCapacity)
void                 trimToSize()
void                 removeRange(int fromIndex, int toIndex)

The second part of the ArrayList data structure

  • ArrayList inheritance relationship
java.lang.Object
        java.util.AbstractCollection<E>
              java.util.AbstractList<E>
                    java.util.ArrayList<E>

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {}
  • The relationship between ArrayList and Collection is shown below:

ArrayList contains two important objects: elementData and size

1. elementData is an array of Object[] type. It saves the elements added to the ArrayList. In fact, elementData is a dynamic array. We can execute its initial capacity through the constructor Arraylist (int initialCapacity); if the list is created by constructing Arrlist() with or without parameters, the initial capacity of elementData is set to 10. elementData array The size of will dynamically increase according to the growth of the ArrayList capacity. For the specific growth method, please refer to the ensureCapacity() method of the source code analysis provided below;

2. size is the actual size of the dynamic array, which is the actual size of elementData (actual length)

Part 3: ArrayList source code analysis

This part is also a more important part, in order to better understand the principle of Arraylist, as well as the author's thinking, the source code is analyzed. The underlying data structure of ArrayList is an array, which is implemented through an array. It is easier to understand from the source code.

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    private static final long serialVersionUID = 8683452581122892189L;
    //1.RandomAccess:(标记接口)代表支持随机访问
    // 2.Cloneable:(标记接口)代表 Object.clone() 方法可以合法地对该类实例进行按字段复制。(
    //3.没有实现 Cloneable 接口的实例上调用 Object 的 clone 方法,则会导致抛出 CloneNotSupportedException 异常)
    //4.java.io.Serializable(标记接口)
    /**
     * 默认初始化的容量
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 指定该ArrayList容量为0时,返回该空数组
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * 用于默认大小的空实例的共享空数组实例。
     * 这个空数组的实例用来给无参构造使用。当调用无参构造方法,返回的是该数组。
     * 将此与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元素的数组缓冲区
     * ArrayList的容量(capacity)就是是此数组缓冲区的长度。
     * 声明为transient 不会被序列化
     * 非私有 是为了方便内部类调用
     * <p>
     * <p>
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;

    /**
     * 构造具有指定初始容量的空列表
     * Constructs an empty list with the specified initial capacity.
     * initialCapacity列表的初始容量
     *
     * @param initialCapacity the initial capacity of the list
     *                        如果指定的值是负数则抛出异常
     * @throws IllegalArgumentException if the specified initial capacity
     *                                  is negative
     */
    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);
        }
    }

    /**
     * 构造一个初始容量为10的空列表
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    /**
     * 构造一个包含指定集合元素的列表
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    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;
        }
    }

    /**
     * Trims the capacity of this <tt>ArrayList</tt> instance to be the
     * list's current size.  An application can use this operation to minimize
     * the storage of an <tt>ArrayList</tt> instance.
     */
//将当前容量设为等于实际元素个数
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
                    ? EMPTY_ELEMENTDATA
                    : Arrays.copyOf(elementData, size);
        }
    }

    /**
     * Increases the capacity of this <tt>ArrayList</tt> instance, if
     * necessary, to ensure that it can hold at least the number of elements
     * specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                // any size if not default element table
                ? 0
                // larger than default for default empty table. It's already
                // supposed to be at default size.
                : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        //因为如果是空的话,minCapacity=size+1;其实就是等于1,空的数组没有长度就存放不了,
        // 所以就将minCapacity变成10,也就是默认大小,到这里,还没有真正的初始化这个elementData的大小。
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

    private void ensureCapacityInternal(int minCapacity) {
        //用来得到一个数组的大小
        int num = calculateCapacity(elementData, minCapacity);
        //这个方法就是实现真正的判断,确认实际的容量,上面只是将minCapacity=10,这个方法就是真正的判断elementData是否够用
        ensureExplicitCapacity(num);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        //判断是否通用,如何添加一个之后的数量大于当前数组的大小,则执行扩容操作
        //分为两种情况:1.第一次进行添加的时候,第一添加的时候,minCapacity是1,在上一个方法中,已经更改为了,已经默认返回数量10,,
        // 到这一步,还没有改变elementData的大小
        //第二种情况:elementData已经不是空数组了,那么在add的时候,minCapacity=size+1,也就是minCapacity代表着要和数组的大小进行比较,看minCapacity
        //和数组的长度进行比较,看数组的长度是否够用,如果够用直接返回添加就好了,如果不够用,需要执行扩容操作,不然增加的这个元素就会溢出。
        if (minCapacity - elementData.length > 0) {
            //扩容的关键方法所在
            grow(minCapacity);
        }
    }

    /**
      The maximum size of array to allocate.
      Some VMs reserve some header words in an array.
      Attempts to allocate larger arrays may result in
      OutOfMemoryError: Requested array size exceeds VM limit
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        //扩容前的数组长度赋值给oldCapacity
        int oldCapacity = elementData.length;
        //newCapacity  后面的运算就是扩容前的数组长度1.5倍进行
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //如果新的长度-默认容量<0;则把初始化的容量赋值给newCapacity
        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:
//往下追究最后就到了native
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) {
            throw new OutOfMemoryError();
        }// overflow
//Arraylist可以进行扩容(针对JDK1.8  数组扩容后的容量是扩容前的1.5倍),Arraylist源码中最大的数组容量是Integer.MAX_VALUE-8,对于空出的8位,目前解释是 :①存储Headerwords;②避免一些机器内存溢出,减少出错几率,所以少分配③最大还是能支持到Integer.MAX_VALUE(当Integer.MAX_VALUE-8依旧无法满足需求时)
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
    }

    /**
     * Returns the number of elements in this list.
     *
     * @return the number of elements in this list
     */
    public int size() {
        return size;
    }

    /**
     * Returns <tt>true</tt> if this list contains no elements.
     *
     * @return <tt>true</tt> if this list contains no elements
     */
    public boolean isEmpty() {
        return size == 0;
    }

    /**
     * Returns <tt>true</tt> if this list contains the specified element.
     * More formally, returns <tt>true</tt> if and only if this list contains
     * at least one element <tt>e</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>.
     *
     * @param o element whose presence in this list is to be tested
     * @return <tt>true</tt> if this list contains the specified element
     */
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

    /**
     * Returns the index of the first occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the lowest index <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
     * or -1 if there is no such index.
     */
//正向查找,返回元素的索引值
    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;
    }

    /**
     * Returns the index of the last occurrence of the specified element
     * in this list, or -1 if this list does not contain the element.
     * More formally, returns the highest index <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>,
     * or -1 if there is no such index.
     */
//反向查找,返回元素索引值
    public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size - 1; i >= 0; i--)
                if (elementData[i] == null)
                    return i;
        } else {
            for (int i = size - 1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

    /**
     * Returns a shallow copy of this <tt>ArrayList</tt> instance.  (The
     * elements themselves are not copied.)
     *
     * @return a clone of this <tt>ArrayList</tt> instance
     */
    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);
        }
    }

    /**
     * Returns an array containing all of the elements in this list
     * in proper sequence (from first to last element).
     * <p>
     * <p>The returned array will be "safe" in that no references to it are
     * maintained by this list.  (In other words, this method must allocate
     * a new array).  The caller is thus free to modify the returned array.
     * <p>
     * <p>This method acts as bridge between array-based and collection-based
     * APIs.
     *
     * @return an array containing all of the elements in this list in
     * proper sequence
     */
//返回Arraylist的Object数组
    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

    /**
     * Returns an array containing all of the elements in this list in proper
     * sequence (from first to last element); the runtime type of the returned
     * array is that of the specified array.  If the list fits in the
     * specified array, it is returned therein.  Otherwise, a new array is
     * allocated with the runtime type of the specified array and the size of
     * this list.
     * <p>
     * <p>If the list fits in the specified array with room to spare
     * (i.e., the array has more elements than the list), the element in
     * the array immediately following the end of the collection is set to
     * <tt>null</tt>.  (This is useful in determining the length of the
     * list <i>only</i> if the caller knows that the list does not contain
     * any null elements.)
     *
     * @param a the array into which the elements of the list are to
     *          be stored, if it is big enough; otherwise, a new array of the
     *          same runtime type is allocated for this purpose.
     * @return an array containing the elements of the list
     * @throws ArrayStoreException  if the runtime type of the specified array
     *                              is not a supertype of the runtime type of every element in
     *                              this list
     * @throws NullPointerException if the specified array is null
     */
// 返回ArrayList的模板数组。所谓模板数组,即可以将T设为任意的数据类型
    @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
  // 若数组a的大小 < ArrayList的元素个数;
  // 则新建一个T[]数组,数组大小是“ArrayList的元素个数”,并将“ArrayList”全部拷贝到新数组中
        if (a.length < size)
            // Make a new array of a's runtime type, but my contents:
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
 // 若数组a的大小 >= ArrayList的元素个数;
 // 则将ArrayList的全部元素都拷贝到数组a中。
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

    // Positional Access Operations

    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

    /**
     * Returns the element at the specified position in this list.
     *
     * @param index index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

    /**
     * Replaces the element at the specified position in this list with
     * the specified element.
     *
     * @param index   index of the element to replace
     * @param element element to be stored at the specified position
     * @return the element previously at the specified position
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E set(int index, E element) {
        rangeCheck(index);

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

    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        //确定内部容量是否够用,size是数组中数据的个数,因为要添加一个元素,所以size+1,
        //先判断size+1这个数组能否放得下,就在这个方法中去判断是否Object[].length是否够用。
        ensureCapacityInternal(size + 1);  // Increments modCount!!
      /*  elementData[size]=e;
        size++;*/
        //执行赋值操作,size并进行加1,增加数组的大小
        elementData[size++] = e;
        return true;
    }

    /**
     * Inserts the specified element at the specified position in this
     * list. Shifts the element currently at that position (if any) and
     * any subsequent elements to the right (adds one to their indices).
     *
     * @param index   index at which the specified element is to be inserted
     * @param element element to be inserted
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
//将e添加到ArrayList中,也很容易去理解,在添加的过程中还有扩容的操作,
//在ensureCapacityInternal中,每次add方法,都要modcount++操作,其目的主要是遍历时,
//迭代器可以有效检查数据结构是否发生变化,简单来说就是数据是否发生变化
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                size - index);
        elementData[index] = element;
        size++;
    }

    /**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).
     *
     * @param index the index of the element to be removed
     * @return the element that was removed from the list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
//删除指定位置的元素
    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; // clear to let GC do its work

        return oldValue;
    }

    /**
     * Removes the first occurrence of the specified element from this list,
     * if it is present.  If the list does not contain the element, it is
     * unchanged.  More formally, removes the element with the lowest index
     * <tt>i</tt> such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
     * (if such an element exists).  Returns <tt>true</tt> if this list
     * contained the specified element (or equivalently, if this list
     * changed as a result of the call).
     *
     * @param o element to be removed from this list, if present
     * @return <tt>true</tt> if this list contained the specified element
     */
//删除list的指定元素
    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 remove method that skips bounds checking and does not
     * return the value removed.
     */
//快速删除第index个元素
    private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
//从index+1位置开始,后面的元素替换前面的所有元素
        if (numMoved > 0)
            System.arraycopy(elementData, index + 1, elementData, index,
                    numMoved);
//将最后一个元素设为null,当发生GC的时候,可以把这个null元素清除掉,因为这里没有任何引用关系,GCRoots不可达(为什么GC roots不可达还需要进行详细进行分析,明白的可以互相交流一下)
        elementData[--size] = null; // clear to let GC do its work
    }

    /**
     * Removes all of the elements from this list.  The list will
     * be empty after this call returns.
     */
    //清空所有元素,并把所有元素都设置为null
    public void clear() {
        modCount++;

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

        size = 0;
    }

    /**
     * Appends all of the elements in the specified collection to the end of
     * this list, in the order that they are returned by the
     * specified collection's Iterator.  The behavior of this operation is
     * undefined if the specified collection is modified while the operation
     * is in progress.  (This implies that the behavior of this call is
     * undefined if the specified collection is this list, and this
     * list is nonempty.)
     *
     * @param c collection containing elements to be added to this list
     * @return <tt>true</tt> if this list changed as a result of the call
     * @throws NullPointerException if the specified collection is null
     */
//将集合C追加到arraylist后面
    public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

    /**
     * Inserts all of the elements in the specified collection into this
     * list, starting at the specified position.  Shifts the element
     * currently at that position (if any) and any subsequent elements to
     * the right (increases their indices).  The new elements will appear
     * in the list in the order that they are returned by the
     * specified collection's iterator.
     *
     * @param index index at which to insert the first element from the
     *              specified collection
     * @param c     collection containing elements to be added to this list
     * @return <tt>true</tt> if this list changed as a result of the call
     * @throws IndexOutOfBoundsException {@inheritDoc}
     * @throws NullPointerException      if the specified collection is null
     */
  // 从index位置开始,将集合c添加到ArrayList
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount

        int numMoved = size - index;
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                    numMoved);

        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }

    /**
     * Removes from this list all of the elements whose index is between
     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
     * Shifts any succeeding elements to the left (reduces their index).
     * This call shortens the list by {@code (toIndex - fromIndex)} elements.
     * (If {@code toIndex==fromIndex}, this operation has no effect.)
     *
     * @throws IndexOutOfBoundsException if {@code fromIndex} or
     *                                   {@code toIndex} is out of range
     *                                   ({@code fromIndex < 0 ||
     *                                   fromIndex >= size() ||
     *                                   toIndex > size() ||
     *                                   toIndex < fromIndex})
     */
//删除fromIndex到toIndex之间的全部元素。
    protected void removeRange(int fromIndex, int toIndex) {
        modCount++;
        int numMoved = size - toIndex;
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                numMoved);

        // clear to let GC do its work
        int newSize = size - (toIndex - fromIndex);
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;
        }
        size = newSize;
    }

    private boolean batchRemove(Collection<?> c, boolean complement) {
        final Object[] elementData = this.elementData;
        int r = 0, w = 0;
        boolean modified = false;
        try {
            for (; r < size; r++)
                if (c.contains(elementData[r]) == complement)
                    elementData[w++] = elementData[r];
        } finally {
            // Preserve behavioral compatibility with AbstractCollection,
            // even if c.contains() throws.
            if (r != size) {
                System.arraycopy(elementData, r,
                        elementData, w,
                        size - r);
                w += size - r;
            }
            if (w != size) {
                // clear to let GC do its work
                for (int i = w; i < size; i++)
                    elementData[i] = null;
                modCount += size - w;
                size = w;
                modified = true;
            }
        }
        return modified;
    }

    /**
     * Save the state of the <tt>ArrayList</tt> instance to a stream (that
     * is, serialize it).
     *
     * @serialData The length of the array backing the <tt>ArrayList</tt>
     * instance is emitted (int), followed by all of its elements
     * (each an <tt>Object</tt>) in the proper order.
     */
// java.io.Serializable的写入函数
// 将ArrayList的“容量,所有的元素值”都写入到输出流中
    private void writeObject(java.io.ObjectOutputStream s)
            throws java.io.IOException {
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();

        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);

        // Write out all elements in the proper order.
        for (int i = 0; i < size; i++) {
            s.writeObject(elementData[i]);
        }

        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

    /**
     * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
     * deserialize it).
     */
// java.io.Serializable的读取函数:根据写入方式读出
 // 先将ArrayList的“容量”读出,然后将“所有的元素值”读出
    private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;

        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in capacity 从输入流中入读arraylist的容量
        s.readInt(); // ignored

        if (size > 0) {
            // be like clone(), allocate array based upon size not capacity
            int capacity = calculateCapacity(elementData, size);
            SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
            ensureCapacityInternal(size);

            Object[] a = elementData;
            // Read in all elements in the proper order. 从输入流将所有的元素值读出
            for (int i = 0; i < size; i++) {
                a[i] = s.readObject();
            }
        }
    }

    /**
     * Returns a list iterator over the elements in this list (in proper
     * sequence), starting at the specified position in the list.
     * The specified index indicates the first element that would be
     * returned by an initial call to {@link ListIterator#next next}.
     * An initial call to {@link ListIterator#previous previous} would
     * return the element with the specified index minus one.
     * <p>
     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: " + index);
        return new ListItr(index);
    }

    /**
     * Returns a list iterator over the elements in this list (in proper
     * sequence).
     * <p>
     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     *
     * @see #listIterator(int)
     */
    public ListIterator<E> listIterator() {
        return new ListItr(0);
    }

    /**
     * Returns an iterator over the elements in this list in proper sequence.
     * <p>
     * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     *
     * @return an iterator over the elements in this list in proper sequence
     */
    public Iterator<E> iterator() {
        return new Itr();
    }
 
}

to sum up:

1. ArrayList actually saves data through an array, so the underlying data structure is an array. When we use parameterless construction to construct a list, the default capacity of arraylist is 10.

2. When the capacity of the arraylist is not enough to accommodate all elements, the expansion operation will be performed, and the capacity of the arraylist will be reset: the new capacity size is oldCapacity + (oldCapacity >> 1), using the >>1 method compared with jdk1.7 Some changes, from the perspective of my understanding, this efficiency is more efficient than the new capacity of 1.7 = (original capacity x3)/2 + 1, because in the process of parsing and calculation by JVM, it will still be converted to binary. Calculation, in 1.8, directly use the binary shift operation for calculation, that is, 1.5 times the expansion operation.

3. The clone function of ArrayList is to clone all elements into another array. The efficiency of using Array.copy() will be higher, because it is directly operated by the C library through the native method at the bottom Yes, the specific selection depends on your business needs and the amount of data in the list

4. ArrayList implements java.io.Serializable way. When writing to the output stream, write "capacity" first, and then write "each element" in turn; when reading the input stream, read "capacity" first, and then read "each element" in turn.

The fourth part ArrayList traversal method


public class ForTst {

    public static void main(String[] args) {
        List<Integer> ints = new ArrayList();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000000; i++) {
            ints.add(i);
        }
        int size = ints.size();
        for (int i = 0; i < size; i++) {
            ints.get(i);
        }
        System.out.println("fori cost time : " + String.valueOf(System.currentTimeMillis() - start));
        System.out.println("-----------------------------------------------------");
        long start2 = System.currentTimeMillis();
        for (Integer i: ints) {
            ints.get(i);
        }
        System.out.println("foreach cost time : " + String.valueOf(System.currentTimeMillis() - start2));
        System.out.println("-----------------------------------------------------");
        long start3 = System.currentTimeMillis();
        Iterator iterator = ints.iterator();
        while (iterator.hasNext()) {
            iterator.next();
        }
        System.out.println("iterator cost time : " + String.valueOf(System.currentTimeMillis() - start3));
        System.out.println("-----------------------------------------------------");
        long start4 = System.currentTimeMillis();
        ints.stream().forEach(integer -> {int  a = integer;});
        System.out.println("steam cost time : " + String.valueOf(System.currentTimeMillis() - start4));
        System.out.println("-----------------------------------------------------");
        long start5 = System.currentTimeMillis();
        ints.forEach(integer -> {int  a = integer;});
        System.out.println("InterfaceForEach cost time : " + String.valueOf(System.currentTimeMillis() - start5));
        System.out.println("-----------------------------------------------------");
    }
}

The amount of data is different, and the performance of each traversal method is different. If you are interested, you can test it from the range of 1000-100000000.

Test by yourself. It is recommended to use the iterator traversal method. The performance is better. The larger the amount of data, the more obvious the advantages of the iterator will be.

 

Part 5 toArray() exception

When we call toArray() in ArrayList, we may encounter a situation where "java.lang.ClassCastException" is thrown. Let's talk about what happened next.

ArrayList provides 2 toArray() functions:

Object[] toArray()
<T> T[] toArray(T[] contents)

Calling toArray() function will throw "java.lang.ClassCastException", but calling toArray(T[] contents) can return T[] normally.

toArray() throws an exception because toArray() returns an Object[] array. Converting Object[] to other types (for example, converting Object[] to Integer[]) will throw "java. lang.ClassCastException" exception, because Java does not support downcasting . For details, please refer to toArray() in the source code introduction part of ArrayList.java.
The solution to this problem is to call <T> T[] toArray(T[] contents) instead of Object[] toArray().

Calling toArray(T[] contents) to return T[] can be achieved in the following ways.

// toArray(T[] contents)调用方式一
public static Integer[] toArray1(ArrayList<Integer> v) {
    Integer[] newText = new Integer[v.size()];
    v.toArray(newText);
    return newText;
}

// toArray(T[] contents)调用方式二。最常用!
public static Integer[] toArray2(ArrayList<Integer> v) {
    Integer[] newText = (Integer[])v.toArray(new Integer[0]);
    return newText;
}

// toArray(T[] contents)调用方式三
public static Integer[] toArray3(ArrayList<Integer> v) {
    Integer[] newText = new Integer[v.size()];
    Integer[] newStrings = (Integer[])v.toArray(newText);
    return newStrings;
}

 

 

Guess you like

Origin blog.csdn.net/crossroads10/article/details/99704509