ArrayList初始容量和扩容机制内容部分源码分析,以及和LinkedList的区别

ArrayList

ArrayList相当于是一个动态类型的顺序表,底层是用数组实现的,所以适合随机的查找和遍历,不适合插入和删除
需要注意的几个点:

  • 初始容量
    调用无参的构造方法时,默认会构造一个初始大小为10的数组,下面是部分源码:
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10;
    
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

有些小伙伴看到这块可能会有点疑惑,DEFAULTCAPACITY_EMPTY_ELEMENTDATA明明初始化是一个空数组,为什么要说构建了一个初始容量为10的空列表呢,见下:

	//只是摘录部分源码 + 本可爱的理解
	public boolean add(E e) {
		//当调用add方法时,首先调用ensureCapacityInternal(int minCapacity)
		//此时因为list里没有元素,所以size = 0,也就是说minCapacity = size + 1 =1,
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    
     private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        	//由于minCapacity =1 < DEFAULT_CAPACITY,所以minCapacity=10;
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }

ArrayList的扩容机制:

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    private void grow(int minCapacity) {
        // 把当前数组的长度记为之前的容量大小
        int oldCapacity = elementData.length;
        // 新的容量 = 旧的容量 + (旧的容量>>1)
        // 也就是说新容量 = 旧容量的1.5倍(>>相当于除以2)
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //如果新容量是否小于最小需要扩容的容量,
        //如果小于则将新容量设为最小需要的容量
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //然后检查新容量是否比数组最大的长度还大
        //如果是则调用hugeCapacity方法继续确定新容量的大小
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 调用数组的copyOf(原始数组, 新数组长度)将原来的elementData内容复制到容量为newCapacity大小的新数组中,并将结果赋给elementData
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

LinkedList

LinkedList 底层是不带头的双向链表,由于是用链表实现的,所以查找慢,但增删元素快

ArrayList和LinkedList区别:

ArrayList LinkedList
存储结构 连续空间 链式结构
是否支持随机访问
任意位置插入/删除元素的时间复杂度 O(N) O(1)
是否需要扩容 在插入期间可能需要扩容(因为底层是连续的空间,空间一旦给好,那么大小就确定好了) 不需要
应用场景 存储+大量访问元素 大量任意位置插入删除元素

Q: 他们两个的空间利用率谁高一些呢?

  • 不能确定,因为:
  1. 单纯从存储空间的角度来看,ArrayList每个节点只需要存储元素就可以 ,而LinkedList除了要存储节点还要存储节点和节点之间的关系
  2. 但是插入期间ArrayList如果需要扩容,因为ArrayList扩容是按照1.5倍扩的,空间没有占满的话,他的利用率会低一点

猜你喜欢

转载自blog.csdn.net/qq_43360037/article/details/105888672