【JDK1.8源码阅读】ArrayList.class(完)

ArrayList储存在Object数组

  • ArrayList数据是储存在 Object[] elementData数据内的。默认初始化是赋予10个元素空间
  • ArrayList在序列化的时候会调用writeObject,直接将size和element写入ObjectOutputStream;反序列化时调用readObject,从ObjectInputStream获取size和element,再恢复到elementData。
  • 为什么不直接用elementData来序列化,而采用上诉的方式来实现序列化呢?原因在于elementData是一个缓存数组,它通常会预留一些容量,等容量不足时再扩充容量,那么有些空间可能就没有实际存储元素,采用上诉的方式来实现序列化时,就可以保证只序列化实际存储的那些元素,而不是整个数组,从而节省空间和时间。(摘: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继承与实现

  1. ArrayList继承于AbstractList,同时实现了List接口
  2. AbstractList继承于AbstractCollection,同样实现了List接口
  3. AbstractCollection实现Collection接口
  4. List接口继承了Collection接口
  5. Collection接口继承了Iterable接口(抱歉,你看到这段文字一定会很不舒服,只能说抱歉了)
//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>

如何增加一个元素

默认增加一个元素不挑位置

  • 先检测空间是否足够,然后直接在size+1位置放入新元素就可以了
	/**
     * 添加一个值,首先会确保容量
     * @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;
    }

向指定位置添加一个元素

Java Native Interface,利用C++在底层实现
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos,int length);

  • 判断index是否越界
  • 在插入位置往后移一个位,然后插入新元素
    /**
     * 在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++;
    }

如何删除一个元素

按下标移除指定元素

  • 对比还有个fastRemove快速删除指定位置的值,不需要检查和返回值,只允许内部使用
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;
    }

按元素删除

  • 原理同indexOf方法,遍历时间复杂度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)根据complement值,将ArrayList中包含c中元素的元素删除或者保留
  • public boolean removeAll(Collection<?> c)ArrayList移除集合c中的所有元素

ArrayList其它内置方法

ArrayList(int initialCapacity)初始化容量

new一个该大小的object数组赋给elementData this.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)构造一个指定的列表

构造一个包含指定c元素的列表,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()缩小空间

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

grow(int minCapacity)扩容判断(私有方法)

私有方法,每一次add的时候都调用该方法判断扩容,elementData = Arrays.copyOf(elementData, newCapacity);先给1.5倍不够再给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)是否包含某对象

调用indexOf判断


 /**
     * 是否包含一个数 返回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()克隆

	/**
     * 返回副本,元素本身没有被复制,复制过程数组发生改变会抛出异常
     * @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);
        }
    }

参考:https://github.com/wupeixuan/JDKSourceCode1.8.git

发布了99 篇原创文章 · 获赞 106 · 访问量 27万+

猜你喜欢

转载自blog.csdn.net/lglglgl/article/details/105058257