[JDK1.8 source code reading] ArrayList.class (end)

ArrayList is stored in Object array

  • ArrayList data stored in Object[] elementDatathe data. The default initialization is to give 10 elements space
  • ArrayList will call writeObject when serializing, directly write size and element to ObjectOutputStream; call readObject when deserializing, get size and element from ObjectInputStream, and then restore to elementData.
  • Why not use elementData to serialize directly, but use the appeal method to achieve serialization? The reason is that elementData is a cache array. It usually reserves some capacity, and then expands the capacity when the capacity is insufficient. Then some space may not have actual storage elements. When serialization is implemented by appeal, you can ensure that only serialization Those elements that are actually stored, not the entire array, thereby saving space and time. (Excerpt: https://blog.csdn.net/zero__007/article/details/52166306)
    private static final int DEFAULT_CAPACITY = 10;//默认容量
    private static final Object[] EMPTY_ELEMENTDATA = {};//空的对象数组
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//默认的空数组,无参构造函数创建的数组
    transient Object[] elementData;//存放数据的数组的缓存变量,不可序列化
    private int size;//元素数量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//数组的最大容量可能会导致内存溢出

ArrayList inheritance and implementation

  1. ArrayList inherits from AbstractList and implements the List interface
  2. AbstractList inherits from AbstractCollection and also implements the List interface
  3. AbstractCollection implements the Collection interface
  4. The List interface inherits the Collection interface
  5. The Collection interface inherits the Iterable interface (sorry, you will be very uncomfortable when you see this text, you can only say sorry)
//ArrayList.java
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable

//AbstractList.java抽象类
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>

//AbstractCollection.java抽象类
public abstract class AbstractCollection<E> implements Collection<E>

//List.java接口
public interface List<E> extends Collection<E>

//Collection.java接口
public interface Collection<E> extends Iterable<E>

//Iterable.java接口
public interface Iterable<T>

How to add an element

Add an element by default without picking a position

  • First check whether the space is enough, and then put the new element directly in the size + 1 position.
	/**
     * 添加一个值,首先会确保容量
     * @param e 要添加到此列表中的元素
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // 扩容
        elementData[size++] = e;// 将e赋值给elementData的size+1的位置
        return true;
    }

Add an element to the specified position

Java Native Interface, using C ++ to implement
public static native void arraycopy (Object src, int srcPos, Object dest, int destPos, int length) at the bottom ;

  • Determine if index is out of bounds
  • Move back one position at the insertion position, then insert a new element
    /**
     * 在ArrayList的index位置,添加元素element,会检查添加的位置和容量
     * @param index   指定元素将被插入的索引
     * @param element 要插入的元素
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public void add(int index, E element) {
        // 判断index是否越界
        rangeCheckForAdd(index);
        // 扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
//src:源数组; srcPos:源数组要复制的起始位置; dest:目的数组; destPos:目的数组放置的起始位置; length:复制的长度
        // 将elementData从index位置开始,复制到elementData的index+1开始的连续空间
        System.arraycopy(elementData, index, elementData, index + 1,
                size - index);
        // 在elementData的index位置赋值element
        elementData[index] = element;
        // ArrayList的大小加一
        size++;
    }

How to delete an element

Remove the specified element by subscript

  • In contrast, there is also a fastRemove to quickly delete the value at the specified position, no need to check and return the value, only internal use is allowed
public E remove(int index) {
        rangeCheck(index);// 判断是否越界
        modCount++;
        E oldValue = elementData(index);// 读取旧值
        // 获取index位置开始到最后一个位置的个数
        int numMoved = size - index - 1;
        if (numMoved > 0)
            // 将elementData数组index+1位置开始拷贝到elementData从index开始的空间
            System.arraycopy(elementData, index + 1, elementData, index, numMoved);
        // 使size-1 ,设置elementData的size位置为空,让GC来清理内存空间
        elementData[--size] = null; //便于垃圾回收器回收
        return oldValue;
    }

Delete by element

  • The principle is the same as indexOf method, traversing time complexity O (n)
	/**
     * 在ArrayList的移除对象为O的元素,跟indexOf方法思想基本一致
     * @param o 要从该列表中删除的元素(如果存在)
     * @return true 如果这个列表包含指定的元素
     */
    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;
    }
  • private boolean batchRemove(Collection<?> c, boolean complement)According to the value of complement, delete or keep the elements in the ArrayList containing the elements in c
  • public boolean removeAll(Collection<?> c)ArrayList removes all elements in set c

ArrayList other built-in methods

ArrayList (int initialCapacity) initial capacity

new an object array of this size is assigned to elementDatathis.elementData = new Object [initialCapacity];

	public ArrayList(int initialCapacity) {
        // 如果初始化时ArrayList大小大于0
        if (initialCapacity > 0) {
            // new一个该大小的object数组赋给elementData
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {// 如果大小为0
            // 将空数组赋给elementData
            this.elementData = EMPTY_ELEMENTDATA;
        } else {// 小于0
            // 则抛出IllegalArgumentException异常
            throw new IllegalArgumentException("Illegal Capacity: " +initialCapacity);
        }
    }
//举例:new ArrayList(88);

ArrayList (Collection <? Extends E> c) constructs a specified list

Construct a list containing the specified c elements, Arrays.copyOf (elementData, size, Object []. Class)

	 /**
     * 带参数Collection的构造方法
     * @param c 其元素将被放入此列表中的集合
     * @throws NullPointerException 如果指定的集合是空的
     */
    public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toarray可能(错误地)不返回对象[](见JAVA BUG编号6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            this.elementData = EMPTY_ELEMENTDATA;// 使用空数组
        }
    }

trimToSize () shrinks space

	/**
     * 因为容量常常会大于实际元素的数量。内存紧张时,可以调用该方法删除预留的位置,调整容量为元素实际数量。
     * 如果确定不会再有元素添加进来时也可以调用该方法来节约空间
     */
    public void trimToSize() {
        modCount++;
        // 如果size小于length
        if (size < elementData.length) {
        // 重新将elementData设置大小为size
            elementData = (size == 0)? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size);
        }
    }

grow (int minCapacity) expansion judgment (private method)

Private method, this method is called to judge expansion every time add, elementData = Arrays.copyOf (elementData, newCapacity); 1.5 times is not enough, then minCapacity

private void grow(int minCapacity) {
        // 获取到ArrayList中elementData数组的内存空间长度
        int oldCapacity = elementData.length;
        // 扩容至原来的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // 再判断一下新数组的容量够不够,够了就直接使用这个长度创建新数组,不够就将数组长度设置为需要的长度
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //若预设值大于默认的最大值检查是否溢出
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 调用Arrays.copyOf方法将elementData数组指向新的内存空间时newCapacity的连续空间
        // 并将elementData的数据复制到新的内存空间
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

contains (Object o) does it contain an object

Call indexOf judgment


 /**
     * 是否包含一个数 返回bool
     * @param o 检测o是否为ArrayList中元素
     * @return true 如果ArrayList中包含o元素
     */
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
    /**
     * 返回一个值在数组首次出现的位置,会根据是否为null使用不同方式判断。不存在就返回-1。时间复杂度为O(N)
     */
    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;
    }

Object clone () clone

	/**
     * 返回副本,元素本身没有被复制,复制过程数组发生改变会抛出异常
     * @return v ArrayList副本
     */
    public Object clone() {
        try {
            // 调用父类(翻看源码可见是Object类)的clone方法得到一个ArrayList副本
            ArrayList<?> v = (ArrayList<?>) super.clone();
            // 调用Arrays类的copyOf,将ArrayList的elementData数组赋值给副本的elementData数组
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            // 返回副本v
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }

Reference: https://github.com/wupeixuan/JDKSourceCode1.8.git

Published 99 original articles · Like 106 · Visit 270,000+

Guess you like

Origin blog.csdn.net/lglglgl/article/details/105058257