Java的ArrayList 扩容机制?

在 Java 集合框架中,ArrayList 是使用最广泛的集合之一。它是基于数组实现的动态数组,具有自动扩容的功能。扩容机制是 ArrayList 的一个重要特性,它让 ArrayList 能够应对动态变化的元素数量。接下来,我们将详细解读 ArrayList 的扩容机制,并结合源码进行说明。

源码解析

我们从 ArrayList 的构造函数和 add 方法入手,逐步揭示其扩容机制。

构造函数

ArrayList 有多个构造函数,其中最常用的是无参构造函数和带初始容量的构造函数。

java

// 无参构造函数
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

// 带初始容量的构造函数
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
    }
}

无参构造函数会将 elementData 初始化为一个默认空数组 DEFAULTCAPACITY_EMPTY_ELEMENTDATA。而带初始容量的构造函数则根据提供的容量大小初始化数组。

add 方法

当我们向 ArrayList 中添加元素时,add 方法会检查是否需要扩容:

java

public boolean add(E e) {
    ensureCapacityInternal(size + 1); // 核心方法,确保容量
    elementData[size++] = e;
    return true;
}

ensureCapacityInternal 方法是扩容机制的核心:

java

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

private void ensureExplicitCapacity(int minCapacity) {
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

当 minCapacity 超过当前数组长度时,会调用 grow 方法进行扩容。

grow 方法

grow 方法是扩容的关键部分:

java

private static final int DEFAULT_CAPACITY = 10;

private void grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1); // 扩容 1.5 倍
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}

扩容的策略是将容量增加到原来的 1.5 倍 (oldCapacity + (oldCapacity >> 1)),同时确保新容量不小于 minCapacity。如果新容量超过了最大数组大小 MAX_ARRAY_SIZE,则调用 hugeCapacity 方法进行特殊处理。

扩容机制设计的目的

扩容机制的设计目的是为了在动态添加元素时,避免频繁的内存分配和数据复制。通过按需扩容,ArrayList 能够高效地管理内存,同时保持灵活性。

性能对比

我们可以通过以下代码示例来对比扩容机制的性能:

java

import java.util.ArrayList;

public class ArrayListPerfTest {
    public static void main(String[] args) {
        // 预先指定容量的 ArrayList
        long startTime = System.nanoTime();
        ArrayList<Integer> listWithCapacity = new ArrayList<>(1000000);
        for (int i = 0; i < 1000000; i++) {
            listWithCapacity.add(i);
        }
        long endTime = System.nanoTime();
        System.out.println("ArrayList with initial capacity: " + (endTime - startTime) + " ns");

        // 默认构造函数的 ArrayList
        startTime = System.nanoTime();
        ArrayList<Integer> listWithoutCapacity = new ArrayList<>();
        for (int i = 0; i < 1000000; i++) {
            listWithoutCapacity.add(i);
        }
        endTime = System.nanoTime();
        System.out.println("ArrayList without initial capacity: " + (endTime - startTime) + " ns");
    }
}

运行上述代码可以发现,预先指定容量的 ArrayList 性能更好,因为它避免了多次扩容操作。

实际应用场景
  1. 动态数据集合:在需要频繁添加元素的场景中,ArrayList 的扩容机制可以保证集合的动态性和灵活性。
  2. 大数据处理:在处理大数据集时,预先指定容量可以提高性能,减少扩容带来的开销。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值