动态数组详解与实战应用 - 掌握ArrayList的使用和特性
ArrayList是Java集合框架中最常用的动态数组实现,它基于数组实现,支持动态扩容,是List接口的一个重要实现类。ArrayList允许存储任何类型的对象(包括null),并且保持元素的插入顺序。
ArrayList会根据需要自动扩容,初始容量为10,每次扩容为原来的1.5倍。
ArrayList保持元素的插入顺序,支持通过索引快速访问元素。
ArrayList允许存储重复的元素,也可以存储null值。
ArrayList不是线程安全的,多线程环境下需要额外的同步措施。
import java.util.ArrayList;
import java.util.List;
// 方式1:默认构造函数(初始容量为10)
ArrayList<String> list1 = new ArrayList<>();
// 方式2:指定初始容量
ArrayList<String> list2 = new ArrayList<>(20);
// 方式3:从其他集合创建
List<String> sourceList = List.of("Java", "Python", "C++");
ArrayList<String> list3 = new ArrayList<>(sourceList);
// 方式4:使用接口引用(推荐)
List<String> list4 = new ArrayList<>();
List<String> languages = new ArrayList<>();
// 在末尾添加元素
languages.add("Java");
languages.add("Python");
languages.add("JavaScript");
// 在指定位置插入元素
languages.add(1, "C++");
// 添加多个元素
List<String> newLanguages = List.of("Go", "Rust");
languages.addAll(newLanguages);
// 在指定位置插入多个元素
languages.addAll(2, List.of("C#", "Swift"));
List<String> fruits = new ArrayList<>();
fruits.addAll(List.of("苹果", "香蕉", "橙子", "葡萄"));
// 通过索引获取元素
String first = fruits.get(0); // 获取第一个元素
String last = fruits.get(fruits.size() - 1); // 获取最后一个元素
// 获取元素索引
int index = fruits.indexOf("橙子"); // 返回2
int notFound = fruits.indexOf("西瓜"); // 返回-1
// 修改指定位置的元素
String oldFruit = fruits.set(1, "草莓"); // 将"香蕉"替换为"草莓"
// 检查是否包含元素
boolean hasApple = fruits.contains("苹果"); // true
List<String> numbers = new ArrayList<>();
numbers.addAll(List.of("1", "2", "3", "4", "5", "3"));
// 通过索引删除
String removed = numbers.remove(0); // 删除第一个元素
// 通过对象删除(删除第一个匹配的)
boolean isRemoved = numbers.remove("3"); // 删除第一个"3"
// 批量删除
List<String> toRemove = List.of("2", "4");
numbers.removeAll(toRemove);
// 条件删除(Java 8+)
numbers.removeIf(n -> Integer.parseInt(n) > 3);
// 清空所有元素
numbers.clear();
List<String> list = Arrays.asList("A", "B", "C", "D");
// 方式1:传统for循环
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
// 方式2:增强for循环(推荐)
for (String item : list) {
System.out.println(item);
}
// 方式3:迭代器
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println(item);
// 可以安全删除元素
// iterator.remove();
}
// 方式4:Stream API(Java 8+)
list.stream().forEach(System.out::println);
操作 | 时间复杂度 | 说明 |
---|---|---|
添加到末尾 | O(1) | 摊销时间复杂度,偶尔需要扩容 |
插入到指定位置 | O(n) | 需要移动后续元素 |
删除末尾元素 | O(1) | 直接删除,无需移动元素 |
删除指定位置 | O(n) | 需要移动后续元素 |
随机访问 | O(1) | 基于数组索引,非常快 |
查找元素 | O(n) | 线性查找,需要遍历 |
// ArrayList扩容机制
初始容量:10(默认构造函数)
扩容公式:newCapacity = oldCapacity + (oldCapacity >> 1)
扩容倍数:1.5倍
// 示例:容量变化过程
10 → 15 → 22 → 33 → 49 → 73 → 109 → ...
特性 | ArrayList | LinkedList | Vector | Array |
---|---|---|---|---|
随机访问 | O(1) ✅ | O(n) ❌ | O(1) ✅ | O(1) ✅ |
插入/删除(头部) | O(n) ❌ | O(1) ✅ | O(n) ❌ | O(n) ❌ |
插入/删除(尾部) | O(1) ✅ | O(1) ✅ | O(1) ✅ | 固定大小 |
线程安全 | 否 ❌ | 否 ❌ | 是 ✅ | 否 ❌ |
内存占用 | 较少 ✅ | 较多 ❌ | 较少 ✅ | 最少 ✅ |
动态大小 | 是 ✅ | 是 ✅ | 是 ✅ | 否 ❌ |
存储用户选择的商品,支持添加、删除、修改数量等操作。
管理学生成绩列表,支持查询、排序、统计等功能。
对数据进行过滤、映射、排序等操作,配合Stream API使用。
实现数据分页显示,通过subList()方法获取指定页面数据。
ArrayList不是线程安全的。在多线程环境下,如果多个线程同时修改ArrayList,可能导致数据不一致或抛出异常。解决方案:
ArrayList在删除元素时不会自动缩容,可能造成内存浪费。如果需要释放内存,可以调用trimToSize()方法。
在使用增强for循环或迭代器遍历时,不能直接修改ArrayList结构(添加或删除元素),否则会抛出ConcurrentModificationException。应该使用迭代器的remove()方法或removeIf()。