在Java编程中,动态数组是一种能够根据元素数量自动调整容量的数据结构,相较于静态数组(固定长度),它提供了更灵活的操作方式,无需预先指定大小即可动态存储数据,Java中实现动态数组的核心类是ArrayList,位于java.util包下,它基于数组实现,并封装了自动扩容、元素管理等逻辑,是开发中常用的集合类之一。

动态数组的创建与初始化
使用ArrayList前,需先创建实例并指定元素类型(通过泛型保证类型安全),初始化方式主要有两种:无参构造(默认初始容量为10)和指定容量构造(适合已知数据量场景,减少扩容次数)。
// 无参构造,默认初始容量10 ArrayList<String> list1 = new ArrayList<>(); // 指定初始容量(例如20) ArrayList<Integer> list2 = new ArrayList<>(20); // 初始化时直接添加元素(基于Arrays.asList的简化写法) ArrayList<Double> list3 = new ArrayList<>(Arrays.asList(1.1, 2.2, 3.3));
核心操作:增删改查
ArrayList提供了丰富的API,支持元素的添加、删除、修改和查询,操作直观且高效。
添加元素
- 尾部添加:使用
add(E element)方法,元素会被追加到数组末尾,时间复杂度O(1)(未触发扩容时)。 - 指定位置插入:使用
add(int index, E element),会将元素插入到指定索引位置,后续元素自动后移,时间复杂度O(n)。
list1.add("Java"); // 尾部添加"Java"
list1.add(1, "Python"); // 在索引1处插入"Python"
删除元素
- 按索引删除:
remove(int index)会移除指定位置的元素,并返回被删除元素,后续元素前移,时间复杂度O(n)。 - 按对象删除:
remove(Object obj)会移除第一个匹配的元素,需注意元素类型与泛型一致,时间复杂度O(n)。
list1.remove(0); // 删除索引0的元素
list1.remove("Python"); // 删除"Python"
修改元素
通过set(int index, E element)方法,可修改指定索引的元素,原值被覆盖,时间复杂度O(1)。

list1.set(0, "C++"); // 将索引0的元素改为"C++"
查询元素
- 按索引获取:
get(int index)返回指定索引的元素,时间复杂度O(1)。 - 查询元素是否存在:
contains(Object obj)返回布尔值,表示是否包含指定元素,时间复杂度O(n)。 - 获取大小:
size()返回当前元素数量,非数组容量。
String first = list1.get(0); // 获取索引0的元素
boolean hasJava = list1.contains("Java"); // 是否包含"Java"
int size = list1.size(); // 获取元素数量
动态数组的核心机制:自动扩容
ArrayList的“动态”特性源于其自动扩容机制,当元素数量达到当前容量时,会触发扩容操作:
- 扩容规则:默认扩容为原容量的1.5倍(使用
Arrays.copyOf创建新数组),可通过ensureCapacity(int minCapacity)手动指定最小容量。 - 扩容成本:扩容需要创建新数组并复制旧数组元素,时间复杂度O(n),因此若预知数据量,建议通过构造方法指定初始容量,避免频繁扩容。
list1.ensureCapacity(20); // 手动确保容量至少为20
遍历与转换
遍历ArrayList是常见操作,支持多种方式:
- for循环:通过索引遍历,适合需要修改元素的场景。
- 增强for循环:简洁直观,适合只读遍历。
- 迭代器:支持安全删除(避免并发修改异常),使用
iterator()或listIterator()获取。
// for循环遍历
for (int i = 0; i < list1.size(); i++) {
System.out.println(list1.get(i));
}
// 增强for循环遍历
for (String item : list1) {
System.out.println(item);
}
// 迭代器遍历(安全删除)
Iterator<String> iterator = list1.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (item.equals("C++")) {
iterator.remove(); // 安全删除当前元素
}
}
ArrayList可转换为数组,使用toArray(T[] array)方法(需指定类型数组)或toArray()(返回Object数组)。

// 转换为String数组 String[] array = list1.toArray(new String[0]);
性能注意事项
- 随机访问快:基于数组实现,
get(int index)时间复杂度O(1),适合频繁查询场景。 - 中间插入/删除慢:插入或删除中间元素时,需移动后续元素,时间复杂度O(n),若需频繁增删,建议改用
LinkedList。 - 线程不安全:
ArrayList非线程安全,多线程环境下需使用Collections.synchronizedList或CopyOnWriteArrayList。
与静态数组的对比
| 特性 | 静态数组([]) |
动态数组(ArrayList) |
|---|---|---|
| 长度 | 固定,初始化后不可变 | 动态可变,自动扩容 |
| 内存管理 | 需手动分配和释放 | 自动管理,无需关注底层内存 |
| 操作灵活性 | 简单但受限 | 丰富,支持增删改查、遍历等 |
| 适用场景 | 数据量固定、高性能场景 | 数据量不确定、频繁增删查的场景 |
ArrayList作为Java中动态数组的实现,通过自动扩容和丰富的API,解决了静态数组长度固定的痛点,成为开发中处理动态数据的首选,理解其核心机制(如扩容、性能特点)和操作方法,能帮助我们更高效地使用它,同时根据场景选择合适的数据结构,提升程序性能,无论是日常业务开发还是算法实现,掌握ArrayList都是Java编程的基础技能。












