[Java collection source code] ArrayList source code analysis

ArrayList

1. Concept

ArrayList is an implementation class of the List interface. The bottom layer is implemented based on arrays. It has the characteristics of fast query, slow addition and deletion, non-thread safety and high efficiency . At the same time, ArrayList also has the ordered and repeatable features of the List interface , and allows insertion of null values.

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

image-20210801210657567

2. Source code analysis

(If there are no special instructions, we generally take JDK1.8 for analysis)

We mainly look at the dynamic expansion mechanism of ArrayList:

2.1, basic properties

private static final int DEFAULT_CAPACITY = 10;//默认容量为 10

private static final Object[] EMPTY_ELEMENTDATA = {
    
    }; //有参构造为 0 时的空数组

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
    
    };//无参构造时的空数组

transient Object[] elementData //不可序列化的对象数组
    
private int size; //实际元素个数

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 最大容量

2.2, the construction method

image-20210801144624992

public ArrayList() {
    
    
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
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);
        }
    }
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;
        

2.3, the main method

We mainly talk about the dynamic expansion mechanism of ArrayList, this process will involve the use of the main methods:

  • When ArrayList uses the no-argument constructor, the default initial elementData is 0; when it is added for the first time

    When adding, the capacity is set to 10; if the capacity is expanded again, the capacity is 1.5 times that of elementData.

  • When using the parameterized constructor constructor, the default initial size of ArrayList is the specified size, and it will be expanded by 1.5 times the size of elementData when it is expanded again.

The method execution process of the expansion mechanism:

When performing element addition, the size is initially 0, that is, each time one is added, the capacity is also increased by one, which is very space-saving!

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

ensureCapacityInternal internal method, takes the most economical capacity as the minimum capacity. It can be seen that the initial elementData is 0 when the empty parameter is constructed, so the minimum capacity is set to DEFAULT_CAPACITY equal to 10 when adding for the first time;

private void ensureCapacityInternal(int minCapacity) {
    
    
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
    
    
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

Then execute the real expansion logic ensureExplicitCapacity, if and only when the minimum capacity (that is, the actual length) begins to exceed the buffer length, execute the second expansion mechanism grow method;

 private void ensureExplicitCapacity(int minCapacity) {
    
    
        modCount++; //表示修改次数

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

First take the actual size of the current elementData, and then execute the newCapacity = oldCapacity + (oldCapacity >> 1)mechanism, so that the new array capacity is 1.5 times the previous (10);

If the new expanded capacity is still less than the current minimum capacity, the current minimum capacity is the new expanded capacity;

If the new expansion capacity is greater than the critical value, a huge capacity is allocated;

The final expanded array is an append copy based on the current array and the new expanded capacity.

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

If the desired capacity is greater than MAX_ARRAY_SIZE, assign Integer.MAX_VALUE, otherwise assign MAX_ARRAY_SIZE.其中:MAX.VALUE 为 0x7fffffff,转换成十进制就是 2147483647,也就是数组的最大长度是 2147483639

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

Reference link

Guess you like

Origin blog.csdn.net/qq_40589204/article/details/119304867