Interpretation of ArrayList source code

Keywords: Java less Attribute JDK

Interpretation of ArrayList source code

attribute

   
    private static final int DEFAULT_CAPACITY = 10;//Default initialization space

    private static final Object[] EMPTY_ELEMENTDATA = {};//Empty array for empty object initialization

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    transient Object[] elementData; //Storage array, non private simplifies nested class access

    private int size;//Amount of data actually stored
    
    protected transient int modCount = 0;//The number of times the collection has been operated. If the number of times does not match, the ConcurrentModificationException() will be thrown;

Construction method

Construction method of setting initial space size

 public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {//If it is greater than 0, an Object array of corresponding length will be constructed
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {//Assign empty array object directly when equal to 0
            this.elementData = EMPTY_ELEMENTDATA;
        } else {//Throw an exception if it is less than 0
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

Nonparametric construction method

 public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;//Assign empty array objects directly
    }

The construction method of parameter of set subclass

 public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();//Parameter c is the class that implements Collection, and toArray is the method defined for the Collection interface
        if ((size = elementData.length) != 0) {
            if (elementData.getClass() != Object[].class)//The return type of Arrays.copyOf depends on the type of the first parameter. To prevent Arrays.copyOf from not returning Object [] type data, see https://bugs.openjdk.java.net/browse/JDK-6260652 for bugs
                elementData = Arrays.copyOf(elementData, size, Object[].class);//Note here that only the actual data length is copied
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;//If the length of the c parameter set is 0, then the elementData is assigned to an empty array object
        }
    }

Basic method

Trimtosize elementdata length trim to actual storage data length

 public void trimToSize() {
        modCount++;//Operand +1
        if (size < elementData.length) {//If the actual storage quantity is less than the length of elementData
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA//If the actual storage is 0, then the elementData assignment is an empty array object
              : Arrays.copyOf(elementData, size);//Otherwise, copy the data of the actual storage length
        }
    }

Ensure that the elementData can hold at least minCapacity data

  public void ensureCapacity(int minCapacity) {
        if (
        minCapacity > elementData.length//The minimum capacity is greater than the current elementData length
            && 
        !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA&& minCapacity <= DEFAULT_CAPACITY)//elementData is not equal to an empty array object and the minimum capacity is greater than the default space (10)
        ) {
            modCount++;//Operand +1
            grow(minCapacity);//Expand the array if the condition is met
        }
    }

grow extended array

  private Object[] grow() {
        return grow(size + 1);//Expand according to the actual storage data amount + 1
    }

grow(int minCapacity) extended array

private Object[] grow(int minCapacity) {
        return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity));//Copy array, return with length of newCapacity(minCapacity)
    }

newCapacity(int minCapacity) returns a capacity at least as large as the given minimum capacity

 private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;//Get old elementData length
        int newCapacity = oldCapacity + (oldCapacity >> 1);//The new length is 1.5 times the old one
        if (newCapacity - minCapacity <= 0) {//If the new length is smaller than the minimum capacity
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                return Math.max(DEFAULT_CAPACITY, minCapacity);//If elementData is empty, return the larger of 10 and minimum capacity
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();//Negative minimum capacity not allowed
            return minCapacity;//If the new length is smaller than the minimum capacity, return the minimum capacity directly
        }
        return (newCapacity - MAX_ARRAY_SIZE <= 0)//If the new length is smaller than the maximum length, the new capacity is returned, otherwise the return value of hugeCapacity(minCapacity) is returned
            ? newCapacity
            : hugeCapacity(minCapacity);
    }

hugeCapacity(int minCapacity) returns large capacity

 private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();//Negative minimum capacity not allowed
        return (minCapacity > MAX_ARRAY_SIZE)
            ? Integer.MAX_VALUE//If the minimum capacity is greater than the maximum value of Integer, return the maximum value of Integer
            : MAX_ARRAY_SIZE;//Otherwise, return Max array size (max array size = integer.max value - 8;)
    }

size returns the number of data actually stored

public int size() {
        return size;
    }

isEmpty determines whether the actual stored data is empty

  public boolean isEmpty() {
        return size == 0;
    }

contains determines whether an element exists

 public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }

indexOf gets an element location

  public int indexOf(Object o) {
        return indexOfRange(o, 0, size);
    }

indexOfRange(Object o, int start, int end) range to query the location of target data in the collection

   int indexOfRange(Object o, int start, int end) {
        Object[] es = elementData;
        if (o == null) {//If the target data is empty
            for (int i = start; i < end; i++) {//Loop from start to end
                if (es[i] == null) {
                    return i;//If the data is null, the corresponding subscript is returned
                }
            }
        } else {//Target data is not empty
            for (int i = start; i < end; i++) {//Loop from start to end
                if (o.equals(es[i])) {//It's important to call the equals method of the target function
                    return i;
                }
            }
        }
        return -1;
    }

lastIndexOf(Object o) finds the last occurrence of an element

 public int lastIndexOf(Object o) {
        return lastIndexOfRange(o, 0, size);
    }

Last indexofrange (object o, int start, int end) query element last occurrence (i.e. reverse first occurrence)

 int lastIndexOfRange(Object o, int start, int end) {
        Object[] es = elementData;
        if (o == null) {//If the target data is empty
            for (int i = end - 1; i >= start; i--) {//From end-1
                if (es[i] == null) {
                    return i;
                }
            }
        } else {
            for (int i = end - 1; i >= start; i--) {
                if (o.equals(es[i])) {//It's important to call the equals method of the target function
                    return i;
                }
            }
        }
        return -1;
    }

Hang in the air...

Posted by The_Assistant on Sat, 02 Nov 2019 11:09:12 -0700