ArrayList与LinkedList的扩容

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ArrayList与LinkedList的扩容相关的知识,希望对你有一定的参考价值。

参考技术A 我们都知道数组不能扩容,ArrayList可以扩容,但ArrayList的底层是数组,他是怎么进行扩容的呢?

一、ArrayList扩容实现步骤

1.扩容: 把原来的数组复制到另一个内存空间更大的数组中;

 2.添加元素: 把新元素添加到扩容以后的数组中。

二、源码分析

关键属性:

解析ArrayList的三个构造方法:

分析常用方法:

LinkedList的扩容机制又是怎么样的呢?

1.LinkedList是一个继承于AbstractSequentialList的双向链表。

2.由于他的底层是用双向链表实现的,没有初始化大小,所以没有油扩容机制,就是一直在前面或者是后面新增就好。

二者区别:

二者的顶层接口都是Collection,

ArrayList是基于数组实现的,查询速度较快,LinkedList是双向链表,可以从头插入也可以从末尾插入,所以在增加和删除的时候比较快,是基于链式存储结构的。

LinkedList是离散空间所以不需要主动扩容,而ArrayList是连续空间,内存空间不足时,会主动扩容。

两者都不是线程安全的

参考资料:

【Java基础】ArrayList 扩容原理

ArrayList详解,看这篇就够了

ArrayList与LinkedList的区别 ?


区别

  1. 数据结构不同。Array是数组,Linked是链表。
  2. 适用场景不同。由于结构不同,Array更适合随机查询,而Linked更适合删除和添加。由于结构不同,导致两者对查询,新增和删除的时间复杂度不同。
  3. 由于LinkedList实现了Deque接口,因此LinkedList可以作为队列使用。
  4. ArrayList添加元素时需要计算扩容,由于LinkedList是双链表,因此LinkedList是不要扩容的。

相同点

  1. ArrayList和LinkedList都实现了List接口
  2. 都可以作为列表使用,只是作为列表时的查询,新增,删除的时间复杂度不同。

ArrayList与LinkedList的add谁更快 ?

这里没有标准答案 ?

如果向尾部添加一个元素

如果ArrayList新增时不需要扩容,理论上不需要再去申请新的内存因此ArrayList更快。

如果ArrayList新增元素时需要进行扩容,则LinkedList更快,ArrayList每次扩容都会扩容当前的1.5倍,代价还是很昂贵的(具体见下方简介)。

如果向中间位置添加元素

由于ArrayList需要移动元素,因此LinkedList更快。


java集合框架图

ArrayList扩容

每次向ArrayList添加元素时,都会计算元素的数量是否已经超出数组的容量,如果超出,数组将会进行扩容,以满足添加数据的需求。ArrayList扩容是通过一个公开的方法ensureCapacity(int minCapacity)来实现。

在实际添加大量元素前,我也可以使用ensureCapacity来手动增加ArrayList实例的容量,以减少递增式再分配的数量。

数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长大约是其原容量的1.5倍。

这种操作的代价是很高的,因此在实际使用时,我们应该尽量避免数组容量的扩张:

  1. 创建ArrayList实例时,就指定其容量,以避免数组扩容的发生。
  2. 根据实际需求,通过调用ensureCapacity方法来手动增加ArrayList实例的容量。

新增时源代码

 public boolean add(E e) 
        ensureCapacityInternal(size + 1);  // 计算容量
        elementData[size++] = e;
        return true;
    

扩容源代码


	//可通过该方法手动扩容
    public void ensureCapacity(int minCapacity) 
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // any size if not default element table
            ? 0
            // larger than default for default empty table. It's already
            // supposed to be at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) 
            ensureExplicitCapacity(minCapacity);
        
    

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

        ensureExplicitCapacity(minCapacity);
    

    private void ensureExplicitCapacity(int minCapacity) 
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

	// 最终执行扩容的方法
    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);
    

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

扩容过程如下图所示 :

以上是关于ArrayList与LinkedList的扩容的主要内容,如果未能解决你的问题,请参考以下文章

ArrayList与LinkedList的区别 ?

ArrayList与LinkedList的区别 ?

ArrayList和LinkedList

LinkedList插入数据效率不一定比ArrayList高,源码分析+实验对比

Java -- ArrayList扩容机制LinkedList vs ArrayListIterator(Fail-Fast机制Fail-Safe机制)HashMap常见面试题

ArrayList,HashMap,LinkedList 初始化大小和 扩容机制