ArrayList source code analysis (unfinished)

ArrayList source code analysis

Introduction

​ Features: ArrayList is the main implementation class of the List interface, which stores ordered and repeatable data.

​ Advantages and disadvantages: ArrayList thread is not safe, but its query and data modification efficiency is high.

​ The underlying principle: The bottom layer of ArrayList is implemented based on arrays.

Inheritance and implementation of Arraylist

Class diagram of ArrayList (the diagram is automatically generated by Idea)

Insert picture description here
As can be seen from the above figure, ArrayList inherits AbstractList and implements Serializable, RandomAccess, Cloneable, and List.

Features:

  • Inherit the AbstractList class and implement the List interface. It is an abstract class that implements some position-related operations of List (such as get, set, add, remove). It is the first collection class to implement random access methods, but does not support addition and replacement .
  • Implement the Cloneable interface and rewrite the function clone(), which can be cloned.
  • Implement RandomAccess interface and provide random access function.
  • The Serializable interface is implemented. Therefore, ArrayList supports serialization and can convert objects into a process that can be maintained or transmitted.

Source code analysis

This article will analyze the source code from the perspective of ArrayList use

ArrayList properties

Before reading the source code, we need to understand the meaning of some ArrayList attributes

	// 数组默认的初始容量为10
    private static final int DEFAULT_CAPACITY = 10;

	// 空的Object数组
    private static final Object[] EMPTY_ELEMENTDATA = {
    
    };

	// 空的Object数组,将其与上面的区分开来,EMPTY_ELEMENTDATA用于有参构造函数且参数为0时,而DEFAULTCAPACITY_EMPTY_ELEMENTDATA用于无参构造函数。
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {
    
    };

	// 集合中存放数据的对象,ArrayList的核心
    transient Object[] elementData; 

	// 集合内数据的大小,size初始为0
    private int size;

	// modCount继承于AbstractList,用于记录数组的添加、删除操作次数

Create an ArrayList object

  1. Create an object using a parameterless constructor

    ArrayList arr = new ArrayList();
    

    Use Ctrl+left mouse click in Idea to enter ArrayList.java to view the source code.

    // 可以看出,创建了一个elementData的长度为0的ArrayList对象
    public ArrayList() {
          
          
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    
  2. Use a parameterized constructor to create an object, and the type of the parameter is int.

    // 创建一个长度为initialCapacity的elementData数组
    public ArrayList(int initialCapacity) {
          
          
        // 如果初始容量长度大于0,则从新创建一个Object数组
        if (initialCapacity > 0) {
          
          
            this.elementData = new Object[initialCapacity];
        // 否则如果初始容量为0,则将EMPTY_ELEMENTDATA的地址赋给elementData。  
        } else if (initialCapacity == 0) {
          
          
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
          
          
        // 否则抛出异常    
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
    
  3. Use the parameterized constructor to create an object, and the type of the parameter is Collection.

    // 使用这种方式创建ArrayList对象,会将Collection对象转为Object数组,然后将其拷贝给elementData数组
    public ArrayList(Collection<? extends E> c) {
          
          
        // 将Collection对象转为数组
        Object[] a = c.toArray();
        // 将b数组的长度赋值给size,判断其是否不等于0
        if ((size = a.length) != 0) {
          
          
            if (c.getClass() == ArrayList.class) {
          
          
                // 将a的地址赋给elementData
                elementData = a;
            } else {
          
          
                // 进行拷贝操作
                elementData = Arrays.copyOf(a, size, Object[].class);
            }
        } else {
          
          
            // replace with empty array.
            elementData = EMPTY_ELEMENTDATA;
        }
    }
    

Add data to the arrayList collection

1 、 add (E e)

add(E e) method

Function: This method is to pass in the data and add it to the array in the manner of self-increment of the array.

    public boolean add(E e) {
    
    
        // 判断集合内存储元素的个数加1看其是否可以承受这个容量
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

ensureCapacityInternal(int minCapacity)方法

Function: to ensure that the internal capacity of the array can add new data

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

calculateCapacity(Object[] elementData, int minCapacity)方法

Function: Compare the size of minCapacity(size+1) and DEFAULT_CAPACITY(10), and return the maximum value.

    private static int calculateCapacity(Object[] elementData, int minCapacity) {
    
    
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
    
    
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

ensureExplicitCapacity(int minCapacity)方法

Function: minCapacity, to determine whether its size is greater than the length of the array, if it is greater than the length of the array, the array needs to be expanded

modCount++: The number of modifications of the array +1, and the function of this attribute will be discussed later.

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

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

grow(int minCapacity) method

Function: expand the array

    private void grow(int minCapacity) {
    
    
        // 将数组的长度定义为集合中旧的容量
        int oldCapacity = elementData.length;
        // 将新的容量定义为旧的容量的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // 如果新的容量小于旧的容量,就令新的容量等于旧的容量
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        // 如果新的容量减去最大数组长度(Integer.MAX_VALUE - 8),则令新的容量扩充为int类型的最大取值范围
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 将旧的数组的数据复制到新的数组中去
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

At this point, after the previous judgment on the expansion of the array is completed, new data is added to the array.

elementData[size++] = e;
        return true;

Important: When the collection is initialized, it is an empty array, and only when data is added for the first time, its length will become 10

2、add(int index, E element)

add(int index, E element) method

Function: The function of this method is to insert elements into the collection according to the specified position

    public void add(int index, E element) {
    
    
        // 用于add和addAll的范围检查,判断是否越界,否则抛出异常。
        rangeCheckForAdd(index);

        // 确保数组内部容量可以添加新的数据
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        // 将elementData中从index开始的数据拷贝到elementData从index+1开始的位置。
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        // 将element元素添加到指定的index位置上
        elementData[index] = element;
        // 集合大小+1
        size++;
    }

3、addAll(Collection<? extends E> c)

Function: Add the data in the collection to the arrayList collection

    public boolean addAll(Collection<? extends E> c) {
    
    
        // 将集合转为数组
        Object[] a = c.toArray();
        int numNew = a.length;
        // 确保数组的容量可以添加这些数据,如果不行就扩容
        ensureCapacityInternal(size + numNew);  // Increments modCount
        // 将a数组内的元素添加到elementData[size]之后.
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

Remove the data in the arrayList collection

1、remove(int index)

Function: Remove the element at the specified position

    public E remove(int index) {
    
    
        // 查看index是否不在集合范围中
        rangeCheck(index);

        // 修改次数+1
        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;
    }

2、remove(Object o)

Function: Remove the specified element

// 通过for循环遍历数组,获取需要删除元素的下标,通过remove删除。
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;
    }

3、removeRange(int fromIndex, int toIndex)

Function: Remove elements in the range fromIndex to toIndex

    protected void removeRange(int fromIndex, int toIndex) {
    
    
        // 修改次数+1
        modCount++;
        // 需要向前移动的的长度
        int numMoved = size - toIndex;
        
        // 将toIndex后的元素向前移动numMoved
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                         numMoved);

        // clear to let GC do its work
        int newSize = size - (toIndex-fromIndex);
        // 通过for循环置从newSize开始的元素为空
        for (int i = newSize; i < size; i++) {
    
    
            elementData[i] = null;
        }
        // 更新size的大小
        size = newSize;
    }

Returns the element at the specified position

get(index)

// 先进行范围检查,然后直接返回数组中下标为index的元素    
public E get(int index) {
    
    
    // index不能>=当前集合的大小
    rangeCheck(index);

    return elementData(index);
}

Update the element at the specified position

set(int index, E element)

// 先进行范围检查,然后获取指定位置上的元素,然后存放到oldValue中,将需要更新的元素赋值给elementData[index],最后返回旧的数据。
public E set(int index, E element) {
    
    
    // index不能>=当前集合的大小
    rangeCheck(index);

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

Determine whether a certain element is contained in the collection

contains(Object o)

Function: Determine whether a certain element is included in the collection

public boolean contains(Object o) {
    
    
	// 判断下标是否大于等于0(表示元素存在)
    return indexOf(o) >= 0;
}

indexOf(Object o)

Function: Get the subscript of the element existing in the collection

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;
    }
    // 返回-1表示元素不存在
    return -1;
}

Clear all data in the collection

public void clear() {
    
    
    // 修改次数+1
    modCount++;

    // 使用for循环令数组中全部的元素都为空
    for (int i = 0; i < size; i++)
        elementData[i] = null;

    size = 0;
}

Note: When deleting or clearing elements in the collection, the size of the data in the collection will change, but the length of the array will not change.

Get the elements in the specified range in the collection

subList(int fromIndex, int toIndex)方法

Function: Get the elements in the specified range in the collection

public List<E> subList(int fromIndex, int toIndex) {
    
    
    // 先进性范围检查,查看fromIndex、toIndex是否满足1条件
    subListRangeCheck(fromIndex, toIndex, size);
    
    // 返回一个新创建的SubList对象,将需要获取的范围传入其中。
    return new SubList(this, 0, fromIndex, toIndex);
}

SubList class

Introduction: It is an internal class in the ArrayList class. Its function is the same as that of the ArrayList class. It can get the elements at the specified position in the array instead of intercepting them to become a new array.

Modify, delete, add, and query functions are also defined in the SubList class.

Iterator

iterator() method

Return a newly created Itr object

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

Itr class

Introduction: This class, like the SubList class, is also an internal class. Itr implements the Iterator interface. So we can use it to traverse.

fail-fast mechanism

Introduction: In the use of ArrayList, an exception may be thrown, and most of this exception occurs when using multiple threads.

The name of this exception is ConcurrentModificationException.

Cause: When multiple threads operate on the collection at the same time, a thread iterates on the collection and assigns the modCount of this time period to the expectedModCount property in the Itr class, while other threads operate on the collection in the same time period. modCount will be updated, but expectedModCount will not be updated. There will be a method (checkForComodification()) in the iterator to compare the values ​​of modCount and expectedModCount, so when the two values ​​are not equal, an exception will be thrown . This is the fail-fast mechanism.

At the same time, this is why the ArrayList collection is not safe.

Fail-fast purpose : a mechanism proposed to prevent thread safety issues when reading data. It is a thread safety mechanism.

For details, please refer to this blogger's post.

Reference connection:

https://blog.csdn.net/zymx14/article/details/78394464

In order to solve the thread safety problem, we can use CopyOnWriteArrayList instead of ArrayList.

Guess you like

Origin blog.csdn.net/weixin_43898463/article/details/114668460