Source code interpretation of ArrayList

Properties of class

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    // Version No
    private static final long serialVersionUID = 8683452581122892189L;
    // Default capacity
    private static final int DEFAULT_CAPACITY = 10;
    // Empty object array
    private static final Object[] EMPTY_ELEMENTDATA = {};
    // Default empty object array
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    // Element array
    transient Object[] elementData;
    // Actual element size, default is 0
    private int size;
    // Maximum array capacity
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
}

Constructor

ArrayList(int) constructor

public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) { // Initial capacity greater than 0
            this.elementData = new Object[initialCapacity]; // Initialize element array
        } else if (initialCapacity == 0) { // Initial capacity is 0
            this.elementData = EMPTY_ELEMENTDATA; // Is an empty array of objects
        } else { // If the initial capacity is less than 0, an exception is thrown
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

ArrayList() type constructor

  public ArrayList() { 
        // No parameter constructor, set element array to null 
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

Constructor of type ArrayList (collection <? Extends E >)

    public ArrayList(Collection<? extends E> c) { // Set parameter constructor
        elementData = c.toArray(); // Convert to array
        if ((size = elementData.length) != 0) { // Parameter is a non empty set
            if (elementData.getClass() != Object[].class) // Whether to convert to an Object type array successfully
                elementData = Arrays.copyOf(elementData, size, Object[].class); // Copy if it is not an Object array
        } else { // Set element array to null if set size is null
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

curd

Add (e e e) function

    public boolean add(E e) { // Add element
        ensureCapacityInternal(size + 1); 
        elementData[size++] = e;
        return true;
    }

Ensurcapacityinternal function

private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { // Determine whether the element array is an empty array
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); // Take the larger value
        }
        
        ensureExplicitCapacity(minCapacity);
    }

The ensureExplicitCapacity function is as follows:

private void ensureExplicitCapacity(int minCapacity) {
        // Modification record plus 1
        modCount++;
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

The grow function is as follows:

 private void grow(int minCapacity) {
        int oldCapacity = elementData.length; // Old capacity
        int newCapacity = oldCapacity + (oldCapacity >> 1); // New capacity is 1.5 times the old capacity
        if (newCapacity - minCapacity < 0) // If the new capacity is less than the capacity specified by the parameter, modify the new capacity and handle the situation of 0-10
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0) // New capacity greater than maximum capacity
            newCapacity = hugeCapacity(minCapacity); // Specify new capacity
        // Copy expansion
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

The hugeCapacity function is as follows:

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
          //MAX_ARRAY_SIZE = Integer.MAX_VALUE-8
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

add(int index,E element) function:

    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1); 
        //Underlying native method call
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

set function

public E set(int index, E element) {
        // Check whether the index is legal
        rangeCheck(index);
        // Save old values
        E oldValue = elementData(index);
        // Assign new value
        elementData[index] = element;
        // Return old value
        return oldValue;
    }

indexOf function

// Find whether the specified element exists in the array from the beginning
    public int indexOf(Object o) {
        if (o == null) { // Found element is empty
            for (int i = 0; i < size; i++) // Traverse the array to find the first empty element and return the subscript
                if (elementData[i]==null)
                    return i;
        } else { // Found element is not empty
            for (int i = 0; i < size; i++) // Traverse the array, find the first element equal to the specified element, and return the subscript
                if (o.equals(elementData[i]))
                    return i;
        } 
        // Not found, return empty
        return -1;
    }

The above analysis shows that null is allowed in the ArrayList collection

get function

public E get(int index) {
        // Check whether the index is legal
        rangeCheck(index);

        return elementData(index);
    }

remove function

   public E remove(int index) {
        // Check whether the index is legal
        rangeCheck(index);
        
        modCount++;
        E oldValue = elementData(index);
        // Number of elements to move
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        // The value is null, which is good for GC
        elementData[--size] = null; 
        // Return old value
        return oldValue;
    }

Comparison of Arrays.copyOf and System.arraycopy

1.System.arraycopy

src - Source array.
srcPos - The starting position in the source array.
dest number- Target array.
destPos - The starting position in the target data.
length - The number of group elements to copy.
  public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

Usage: used in add(int index,E e) and remove(int index) functions of ArrayList
Features: new and old arrays are available, just move

2.Arrays.copyOf

original - Array to copy
newLength - Length of replica to return
newType - Type of replica to return
public  static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
       //Math.min(original.length, newLength) to prevent overstepping
        System.arraycopy(original, 0, copy, 0,
                        Math.min(original.length, newLength));
        return copy;
    }

//There are many ways to overload
  public static short[] copyOf(short[] original, int newLength) {...}Wait

Usage: used when expanding ArrayList, and when instantiating ArrayList through the constructor ArrayList (collection <? Extends E > C).
Features: need to create a new array, according to the newType to determine the array type.

The difference is: System.arraycopy is a part of Array.copyOf. When the target array is not created, the latter must be used. If the original array and the target array already exist, use the former by yourself

Tags: Java less

Posted on Mon, 04 May 2020 10:03:56 -0400 by mise_me_fein