[set] ArrayList source code analysis

Keywords: Java

ArrayList source code analysis

1, Structure

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

1) Support generics
2) Inheriting AbstractList, you can use some methods of the abstract class
3) List, which supports the methods in the list interface
4) RandomAccess supports random access
5) Clonable supports object cloning
6) Serializable supports serialization

2, Attributes

 private static final long serialVersionUID = 8683452581122892189L;

    private static final int DEFAULT_CAPACITY = 10;
    private static final Object[] EMPTY_ELEMENTDATA = {};
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    transient Object[] elementData; // non-private to simplify nested class access
    private int size;

1)DEFAULT_CAPACITY default initial capacity = 10
2)EMPTY_ELEMENTDATA empty array
3)DEFAULTCAPACITY_EMPTY_ELEMENTDATA is an empty array. When the first element is inserted, it will be initialized with a length of 10
4) elementData holds the buffer array of elements, and transient means that it will not be serialized
5) size is the number of elements in the collection

3, Method

1. Construction method

1)

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

Build an ArrayList based on the given initial capacity initialCapacity
If initialCapacity > 0, an ArrayList with a capacity of initialCapacity will be created directly
If initialCapacity=0, empty is used directly_ Elementdata empty set
If initialCapacity < 0, an error occurs.
2)

public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

Create an ArrayList with a capacity of 10
3)

public ArrayList(Collection<? extends E> c) {
        Object[] a = c.toArray();
        if ((size = a.length) != 0) {
            if (c.getClass() == ArrayList.class) {
                elementData = a;
            } else {
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
        } else {
            // replace with empty array.
            elementData = EMPTY_ELEMENTDATA;
        }
    }

Convert collection to ArrayList

2. Common examples and methods

1)

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

Add any type of element to the end of ArrayList, and add 1 to the length;
2)

public int size() {
        return size;
    }

Returns the length of the ArrayList directly
3)

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

        return elementData(index);
    }

rangCheck determines whether it is out of bounds and returns the element corresponding to the array subscript
4)

public E set(int index, E element) {
        rangeCheck(index);

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

First, judge whether it is out of bounds, obtain the value in the original array, set the new value element, and return the old value
5)

public void clear() {
        modCount++;

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

        size = 0;
    }

modCount, from its parent class AbstractList, records the number of structural changes in ArrayList. Method sets all the elements in the array to null and the length of the array to 0
6)

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

Inserts an element at the specified location
7)

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

Deletes the element of the specified subscript of the array
8)

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

Deletes the specified element
9)

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

Judge whether it is empty
10)

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

Gets the subscript of the specified element
11)

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

Determines whether the array contains the specified element
12)

 public Iterator<E> iterator() {
        return new Itr();
    }

Returns an iterator, which can be used for traversal

4, Analysis of capacity expansion principle

Expansion is required when adding elements

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

The ensureCapacityInternal(size + 1) here; The method is to judge whether capacity expansion is required

private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

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

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

The actual expansion logic is in the grow th method

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);//The new length is 1.5 times the original length
        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);
    }

ArrayList is equivalent to delaying the allocation of object array space when initialCapacity is not specified. Only 10 (default) object spaces are allocated when the element is inserted for the first time. If 20 data need to be added, the capacity of ArrayList will be changed to 10 for the first time (as shown in Figure 1 below); After that, the capacity expansion will increase by 1.5 times. That is, when the 11th data is added, the ArrayList continues to expand to 10 * 1.5 = 15 (as shown in Figure 2 below); When the 16th data is added, continue to expand to 15 * 1.5 = 22 (as shown in Figure 4 below):

Posted by Unknown User on Wed, 06 Oct 2021 19:26:14 -0700