ArrayList扩容

本文详细解释了Java中的ArrayList如何在运行时动态扩容,包括初始容量设定、添加元素过程、扩容策略以及可能带来的性能影响。
摘要由CSDN通过智能技术生成

在Java中,ArrayList是一个动态数组,它允许在运行时改变其大小。当向ArrayList添加元素并且当前数组容量不足以容纳新元素时,ArrayList会自动扩容。

扩容原理
初始容量:当创建一个新的ArrayList时,可以指定一个初始容量。如果没有指定,则默认容量为10。
添加元素:当向ArrayList添加元素时,会检查当前数组的容量是否足够。如果足够,则直接在数组的末尾添加元素。
容量不足:如果当前数组的容量不足以容纳新元素,则需要进行扩容。扩容的逻辑是创建一个新的数组,其容量大约是原数组容量的1.5倍(具体实现可能因Java版本而异,但大致是这个比例)。然后,将原数组的所有元素复制到新数组中,并释放原数组的内存。最后,将新数组引用赋值给ArrayList的数组引用。
继续添加:扩容完成后,就可以在新数组的末尾添加新元素了。
例如:

import java.util.ArrayList;  
  
public class ArrayListExpansionExample {  
    public static void main(String[] args) {  
        // 创建一个初始容量为3的ArrayList  
        ArrayList<Integer> list = new ArrayList<>(3);  
  
        // 向ArrayList中添加元素  
        for (int i = 0; i < 5; i++) {  
            list.add(i);  
            System.out.println("After adding element " + i + ": " + list);  
            System.out.println("Capacity: " + getArrayListCapacity(list));  
        }  
    }  
    private static int getArrayListCapacity(ArrayList<?> list) {  
        try {  
            java.lang.reflect.Field elementDataField = list.getClass().getDeclaredField("elementData");  
            elementDataField.setAccessible(true);  
            Object[] elementData = (Object[]) elementDataField.get(list);  
            return elementData.length;  
        } catch (NoSuchFieldException | IllegalAccessException e) {  
            throw new RuntimeException(e);  
        }  
    }  
}

运行这段代码,你将看到以下输出

After adding element 0: [0]  
Capacity: 3  
After adding element 1: [0, 1]  
Capacity: 3  
After adding element 2: [0, 1, 2]  
Capacity: 3  
After adding element 3: [0, 1, 2, 3]  
Capacity: 4 (或可能是更大的值,取决于具体的实现和Java版本)  
After adding element 4: [0, 1, 2, 3, 4]  
Capacity: 6 (或更大的值)

ArrayList扩容过程中内存的变化:

假设我们有一个初始容量为4的ArrayList,并且已经存储了3个元素。现在我们要添加第4个元素。

1’初始状态:内存中有一个数组对象,其容量为3,并且存储了3个元素。ArrayList对象持有一个指向这个数组的引用。
2.添加第4个元素:当尝试添加第4个元素时,发现数组容量不足。
3.扩容:Java虚拟机(JVM)在堆内存中分配一个新的数组对象,其容量大约是原数组的1.5倍(这里假设是6)。然后,将原数组的所有元素复制到新数组中。此时,原数组对象变得不再被引用,因此可以被垃圾回收器回收。
4.更新引用:将ArrayList对象的数组引用更新为指向新的数组对象。
5.添加完成:现在可以在新数组的末尾添加第5个元素了。
需要注意的是,这个过程是透明的,对ArrayList的使用者来说是不可见的。我们只需要调用add方法添加元素,而不需要关心底层的扩容逻辑。

此外,频繁的扩容操作可能会导致性能下降,因为每次扩容都需要创建新的数组并复制元素。因此,如果知道要存储的元素数量,最好在创建ArrayList时指定一个合适的初始容量,以减少扩容的次数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值