Appearance
14.2 ArrayList 集合使用
ArrayList 的概念
ArrayList 是 Java 中最常用的集合类之一,它实现了 List 接口,基于数组实现,提供了动态大小的数组功能。ArrayList 允许存储重复元素,并且可以通过索引快速访问元素。
ArrayList 的特点
- 基于数组:底层使用数组实现,支持随机访问
- 动态大小:容量会根据需要自动增长
- 允许重复元素:可以存储相同的元素
- 有序:保持元素的插入顺序
- 非线程安全:在多线程环境中需要额外的同步措施
ArrayList 的创建
1. 无参构造方法
创建一个初始容量为 10 的 ArrayList。
java
ArrayList<String> list = new ArrayList<>();2. 指定初始容量
创建一个指定初始容量的 ArrayList。
java
ArrayList<String> list = new ArrayList<>(20); // 初始容量为 203. 从其他集合创建
通过其他集合创建 ArrayList。
java
List<String> otherList = Arrays.asList("Java", "Python", "C++");
ArrayList<String> list = new ArrayList<>(otherList);ArrayList 的常用方法
1. 添加元素
add(E e)
功能:在列表末尾添加元素
示例:
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");add(int index, E element)
功能:在指定位置添加元素
示例:
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("C++");
list.add(1, "Python"); // 在索引 1 处添加 "Python"addAll(Collection<? extends E> c)
功能:添加指定集合中的所有元素
示例:
java
ArrayList<String> list1 = new ArrayList<>();
list1.add("Java");
list1.add("Python");
ArrayList<String> list2 = new ArrayList<>();
list2.add("C++");
list2.add("JavaScript");
list1.addAll(list2); // list1 现在包含 ["Java", "Python", "C++", "JavaScript"]addAll(int index, Collection<? extends E> c)
功能:在指定位置添加指定集合中的所有元素
示例:
java
ArrayList<String> list1 = new ArrayList<>();
list1.add("Java");
list1.add("C++");
ArrayList<String> list2 = new ArrayList<>();
list2.add("Python");
list2.add("JavaScript");
list1.addAll(1, list2); // list1 现在包含 ["Java", "Python", "JavaScript", "C++"]2. 删除元素
remove(int index)
功能:删除指定索引处的元素
示例:
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
list.remove(1); // 删除索引 1 处的元素 "Python"remove(Object o)
功能:删除指定的元素
示例:
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
list.remove("Python"); // 删除元素 "Python"removeAll(Collection<?> c)
功能:删除指定集合中的所有元素
示例:
java
ArrayList<String> list1 = new ArrayList<>();
list1.add("Java");
list1.add("Python");
list1.add("C++");
list1.add("JavaScript");
ArrayList<String> list2 = new ArrayList<>();
list2.add("Python");
list2.add("C++");
list1.removeAll(list2); // list1 现在包含 ["Java", "JavaScript"]retainAll(Collection<?> c)
功能:保留指定集合中的元素,删除其他元素
示例:
java
ArrayList<String> list1 = new ArrayList<>();
list1.add("Java");
list1.add("Python");
list1.add("C++");
list1.add("JavaScript");
ArrayList<String> list2 = new ArrayList<>();
list2.add("Python");
list2.add("C++");
list1.retainAll(list2); // list1 现在包含 ["Python", "C++"]clear()
功能:清空集合中的所有元素
示例:
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
list.clear(); // 清空集合3. 修改元素
set(int index, E element)
功能:修改指定索引处的元素
示例:
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
list.set(1, "JavaScript"); // 将索引 1 处的元素修改为 "JavaScript"4. 查找元素
get(int index)
功能:获取指定索引处的元素
示例:
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
String element = list.get(0); // 获取索引 0 处的元素 "Java"indexOf(Object o)
功能:获取指定元素第一次出现的索引
示例:
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("Java");
int index = list.indexOf("Java"); // 返回 0lastIndexOf(Object o)
功能:获取指定元素最后一次出现的索引
示例:
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("Java");
int index = list.lastIndexOf("Java"); // 返回 2contains(Object o)
功能:检查集合是否包含指定元素
示例:
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
boolean contains = list.contains("Python"); // 返回 true5. 其他方法
size()
功能:获取集合的大小
示例:
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
int size = list.size(); // 返回 3isEmpty()
功能:检查集合是否为空
示例:
java
ArrayList<String> list = new ArrayList<>();
boolean isEmpty = list.isEmpty(); // 返回 true
list.add("Java");
isEmpty = list.isEmpty(); // 返回 falsetoArray()
功能:将集合转换为数组
示例:
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
Object[] array = list.toArray();toArray(T[] a)
功能:将集合转换为指定类型的数组
示例:
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
String[] array = list.toArray(new String[0]);iterator()
功能:获取集合的迭代器
示例:
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
System.out.println(element);
}ArrayList 的遍历
1. for 循环
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
for (int i = 0; i < list.size(); i++) {
String element = list.get(i);
System.out.println(element);
}2. 增强 for 循环
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
for (String element : list) {
System.out.println(element);
}3. 迭代器
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
System.out.println(element);
}4. forEach 方法(Java 8+)
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("C++");
list.forEach(element -> System.out.println(element));ArrayList 的性能
时间复杂度
| 操作 | 时间复杂度 |
|---|---|
| 随机访问(get/set) | O(1) |
| 头部插入/删除 | O(n) |
| 尾部插入/删除 | O(1) |
| 中间插入/删除 | O(n) |
| 搜索 | O(n) |
空间复杂度
- 空间复杂度:O(n),其中 n 是元素数量
ArrayList 的扩容机制
ArrayList 的初始容量为 10,当元素数量超过当前容量时,会自动扩容。扩容的规则是:
- 当元素数量超过当前容量时,新容量为当前容量的 1.5 倍
- 如果新容量仍然不够,直接使用需要的容量
示例:
java
ArrayList<String> list = new ArrayList<>(); // 初始容量 10
// 添加 10 个元素,容量仍为 10
for (int i = 0; i < 10; i++) {
list.add("Element " + i);
}
// 添加第 11 个元素,容量会扩容到 15 (10 * 1.5)
list.add("Element 10");示例:ArrayList 的使用
示例 1:基本操作
java
import java.util.ArrayList;
public class ArrayListBasicExample {
public static void main(String[] args) {
// 创建 ArrayList
ArrayList<String> languages = new ArrayList<>();
// 添加元素
languages.add("Java");
languages.add("Python");
languages.add("C++");
System.out.println("添加元素后: " + languages);
// 在指定位置添加元素
languages.add(1, "JavaScript");
System.out.println("在指定位置添加元素后: " + languages);
// 修改元素
languages.set(2, "TypeScript");
System.out.println("修改元素后: " + languages);
// 删除元素
languages.remove(3);
System.out.println("删除元素后: " + languages);
// 获取元素
String first = languages.get(0);
System.out.println("第一个元素: " + first);
// 检查元素是否存在
boolean contains = languages.contains("Java");
System.out.println("是否包含 Java: " + contains);
// 获取元素索引
int index = languages.indexOf("TypeScript");
System.out.println("TypeScript 的索引: " + index);
// 获取集合大小
int size = languages.size();
System.out.println("集合大小: " + size);
// 遍历集合
System.out.println("遍历集合:");
for (String language : languages) {
System.out.println("- " + language);
}
// 清空集合
languages.clear();
System.out.println("清空后: " + languages);
System.out.println("清空后大小: " + languages.size());
}
}示例 2:存储自定义对象
java
import java.util.ArrayList;
class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Student{name='" + name + "', age=" + age + "}";
}
}
public class ArrayListObjectExample {
public static void main(String[] args) {
// 创建 ArrayList 存储 Student 对象
ArrayList<Student> students = new ArrayList<>();
// 添加学生对象
students.add(new Student("Alice", 18));
students.add(new Student("Bob", 19));
students.add(new Student("Charlie", 20));
// 打印学生列表
System.out.println("学生列表: " + students);
// 获取学生
Student firstStudent = students.get(0);
System.out.println("第一个学生: " + firstStudent);
// 修改学生
students.set(1, new Student("David", 21));
System.out.println("修改后学生列表: " + students);
// 删除学生
students.remove(2);
System.out.println("删除后学生列表: " + students);
// 遍历学生列表
System.out.println("遍历学生列表:");
for (Student student : students) {
System.out.println("- " + student.getName() + " (" + student.getAge() + "岁)");
}
}
}示例 3:ArrayList 与数组的转换
java
import java.util.ArrayList;
import java.util.Arrays;
public class ArrayListArrayConversionExample {
public static void main(String[] args) {
// 从数组创建 ArrayList
String[] array = {"Java", "Python", "C++"};
ArrayList<String> list = new ArrayList<>(Arrays.asList(array));
System.out.println("从数组创建的 ArrayList: " + list);
// 从 ArrayList 创建数组
String[] newArray = list.toArray(new String[0]);
System.out.println("从 ArrayList 创建的数组: " + Arrays.toString(newArray));
// 从 ArrayList 创建指定大小的数组
String[] newArray2 = list.toArray(new String[list.size()]);
System.out.println("从 ArrayList 创建的指定大小数组: " + Arrays.toString(newArray2));
}
}示例 4:ArrayList 的排序
java
import java.util.ArrayList;
import java.util.Collections;
public class ArrayListSortExample {
public static void main(String[] args) {
// 创建 ArrayList
ArrayList<Integer> numbers = new ArrayList<>();
numbers.add(5);
numbers.add(2);
numbers.add(8);
numbers.add(1);
numbers.add(9);
System.out.println("排序前: " + numbers);
// 升序排序
Collections.sort(numbers);
System.out.println("升序排序后: " + numbers);
// 降序排序
Collections.sort(numbers, Collections.reverseOrder());
System.out.println("降序排序后: " + numbers);
// 字符串排序
ArrayList<String> languages = new ArrayList<>();
languages.add("Java");
languages.add("Python");
languages.add("C++");
languages.add("JavaScript");
System.out.println("字符串排序前: " + languages);
// 按字典序排序
Collections.sort(languages);
System.out.println("字符串排序后: " + languages);
}
}常见问题
1. 索引越界
症状:IndexOutOfBoundsException
解决方案:在访问元素前,确保索引在有效范围内
示例:
java
ArrayList<String> list = new ArrayList<>();
list.add("Java");
// 错误:索引越界
// String element = list.get(1);
// 正确:检查索引范围
if (index >= 0 && index < list.size()) {
String element = list.get(index);
}2. 空指针异常
症状:NullPointerException
解决方案:在使用集合前,检查集合是否为 null
示例:
java
ArrayList<String> list = null;
// 错误:空指针异常
// list.add("Java");
// 正确:检查集合是否为 null
if (list != null) {
list.add("Java");
} else {
list = new ArrayList<>();
list.add("Java");
}3. 性能问题
症状:ArrayList 操作速度慢
解决方案:
- 对于频繁的插入和删除操作,考虑使用 LinkedList
- 合理设置初始容量,减少扩容操作
- 对于大数据量,考虑使用更高效的数据结构
示例:
java
// 合理设置初始容量
ArrayList<String> list = new ArrayList<>(1000); // 初始容量为 1000
// 对于频繁插入删除,使用 LinkedList
List<String> list = new LinkedList<>();4. 线程安全问题
症状:在多线程环境中,ArrayList 操作导致数据不一致
解决方案:使用线程安全的集合或同步机制
示例:
java
// 使用线程安全的集合
List<String> list = Collections.synchronizedList(new ArrayList<>());
// 或使用 CopyOnWriteArrayList
List<String> list = new CopyOnWriteArrayList<>();最佳实践
合理设置初始容量:根据预期的元素数量,合理设置初始容量,减少扩容操作
选择合适的集合:对于频繁的插入和删除操作,考虑使用 LinkedList;对于频繁的随机访问,使用 ArrayList
使用泛型:使用泛型确保类型安全,避免运行时异常
注意线程安全:在多线程环境中,使用线程安全的集合或同步机制
避免不必要的装箱拆箱:对于基本数据类型,考虑使用原始类型的集合(如 IntArrayList)
使用合适的遍历方式:对于 ArrayList,使用索引遍历或增强 for 循环
及时清理:对于不再使用的 ArrayList,及时清空或设置为 null,帮助垃圾回收
总结
ArrayList 是 Java 中最常用的集合类之一,它基于数组实现,提供了动态大小的数组功能。ArrayList 的主要特点:
- 基于数组:支持随机访问,时间复杂度为 O(1)
- 动态大小:容量会根据需要自动增长
- 允许重复元素:可以存储相同的元素
- 有序:保持元素的插入顺序
- 非线程安全:在多线程环境中需要额外的同步措施
ArrayList 适用于需要频繁随机访问元素的场景,而对于频繁插入和删除操作的场景,建议使用 LinkedList。
通过合理使用 ArrayList,可以提高代码的效率和可维护性。
