ArrayList 是 Java 中最常用的动态数组集合类,位于 java.util 包下。它底层基于动态数组实现,支持自动扩容,解决了普通数组长度固定不可修改的痛点。

1.核心特点

  • 动态扩容:容量不足时自动增长,无需手动指定长度
  • 有序可重复:元素按插入顺序存储,允许重复元素、允许存 null
  • 随机访问快:通过索引直接访问元素,时间复杂度 O (1)
  • 非线程安全:多线程环境下不推荐使用(推荐 CopyOnWriteArrayList
  • 底层实现Object[] 数组

2.基础使用

2.1 导包

import java.util.ArrayList;

2. 2 创建 ArrayList

// 1. 无参构造(默认初始容量10)
ArrayList<String> list1 = new ArrayList<>();

// 2. 指定初始容量(推荐,避免频繁扩容)
ArrayList<Integer> list2 = new ArrayList<>(20);

// 3. 泛型:指定存储的数据类型(只能存引用类型,基本类型用包装类)
// 错误:ArrayList<int>  正确:ArrayList<Integer>

2.3 常用方法

public class ArrayListDemo {
    public static void main(String[] args) {
        // 创建存储字符串的ArrayList
        ArrayList<String> fruits = new ArrayList<>();

        // 1. 添加元素 add()
        fruits.add("苹果");
        fruits.add("香蕉");
        fruits.add(0, "草莓"); // 指定索引插入

        // 2. 获取元素 get(索引)
        System.out.println(fruits.get(0)); // 输出:草莓

        // 3. 修改元素 set(索引, 新值)
        fruits.set(1, "芒果");

        // 4. 删除元素 remove(索引) / remove(元素)
        fruits.remove(2); // 删除索引2的元素
        fruits.remove("芒果"); // 删除指定元素

        // 5. 获取长度 size()
        System.out.println("元素个数:" + fruits.size());

        // 6. 判断是否包含 contains()
        System.out.println(fruits.contains("苹果"));

        // 7. 清空集合 clear()
        // fruits.clear();

        // 8. 判断是否为空 isEmpty()
        System.out.println(fruits.isEmpty());
    }
}

2.4 遍历 ArrayList

1.普通 for 循环(通过索引)

for (int i = 0; i < fruits.size(); i++) {
    System.out.println(fruits.get(i));
}

2.增强 for 循环(推荐,简洁)

for (String fruit : fruits) {
    System.out.println(fruit);
}

3.迭代器 Iterator

Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

3. ArrayList 自动扩容机制

  • 无参创建时,初始为空数组,第一次添加元素时扩容为 10
  • 容量满了之后,自动扩容为原容量的 1.5 倍
  • 扩容本质:创建新数组 → 复制旧元素 → 替换旧数组
  • 优化建议:提前指定初始容量,减少扩容次数

4.ArrayList vs 普通数组

特性普通数组ArrayList
长度固定不可变动态自动扩容
存储类型基本类型 + 引用类型仅引用类型(需包装类)
功能简单,无内置方法方法丰富(增删改查)
使用场景固定长度数据长度不确定、频繁操作

5.ArrayList的实现(源码)

5.1 底层数据结构

// 1. 默认初始容量
private static final int DEFAULT_CAPACITY = 10;

// 2. 空实例共享的空数组(无参构造用)
private static final Object[] EMPTY_ELEMENTDATA = {};

// 3. 无参构造专用空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

// 4. 真正存储元素的底层数组【核心】
transient Object[] elementData;

// 5. 实际元素个数(不是数组容量)
private int size;

// 6. 最大数组容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

1. DEFAULT_CAPACITY

private static final int DEFAULT_CAPACITY = 10;
  • 含义:默认初始容量
  • 作用:无参构造创建 ArrayList 后,第一次 add 元素时,底层数组会初始化为长度 10。
  • 不是一 new 就创建长度 10 数组,懒加载

2. EMPTY_ELEMENTDATA

private static final Object[] EMPTY_ELEMENTDATA = {};
  • 空常量数组,有参构造传入容量为 0 时使用。
  • 例如:new ArrayList<>(0) 底层赋值为这个空数组。
  /**
     * Constructs an empty list with the specified initial capacity.
     *
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            // 为0时赋值
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

3. DEFAULTCAPACITY_EMPTY_ELEMENTDATA

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
  • 无参构造 new ArrayList<>() 默认赋值这个空数组
  • 作用:和上面空数组做区分,用来标记「是无参构造创建的」,方便第一次 add 时直接扩容到 10。
  • 两个空数组都是空数组,只是标记身份不同,为了后续扩容逻辑区分

4. elementData 【最核心】

transient Object[] elementData;
  • 底层真正存放所有元素的数组
  • transient:序列化时不直接序列化整个数组,只序列化有效元素,节省空间。
  • 泛型 <E> 只是语法糖,底层全部存 Object,取元素时强转。

5. size

private int size;
  • 实际已存储的元素个数
  • 区别:
    • capacity:底层数组 elementData总容量
    • size真实元素数量
  • 永远满足:size ≤ 数组容量

6. MAX_ARRAY_SIZE

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
  • 允许分配的最大数组大小
  • 减 8 是为了规避部分 JVM 数组头内存溢出问题。
  • 超过这个大小就直接用 Integer.MAX_VALUE

5.2 构造函数

1. 无参构造

public ArrayList() {
    elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
  • 刚创建:底层是空数组,容量 0
  • 第一次 add:自动扩容到 DEFAULT_CAPACITY = 10

2.指定初始容量构造

public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException(...);
    }
}
  • 容量 > 0:直接创建对应长度 Object 数组
  • 容量 = 0:赋值 EMPTY_ELEMENTDATA

3.集合入参构造

public ArrayList(Collection<? extends E> c) {
    // 1. 把传入的集合转成数组,赋值给 elementData
    elementData = c.toArray();

    // 2. 把数组长度赋值给 size,然后判断长度是否为 0
    if ((size = elementData.length) != 0) {
        // 重点:JDK 官方注释:c.toArray() 可能错误地不返回 Object[]
        // 3. 如果数组类型不是 Object[],就强制拷贝成 Object[]
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // 4. 传入空集合,直接用空数组常量
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

把传入集合转数组,赋值给 elementData,并给 size 赋值。

更多推荐