在 Java 编程世界里,集合框架是开发者手中的重要工具,它为数据的存储和操作提供了丰富的选择。本文将聚焦于 List、Set、Map 三大核心接口下的常见实现类,对比 ArrayList 与 LinkedList、HashSet 与 TreeSet、HashMap 与 TreeMap 的底层原理和性能差异,并结合有趣的案例,帮助大家掌握集合的选型与操作技巧。
操作类型 | ArrayList | LinkedList |
---|---|---|
随机访问(get) | 高效 O (1) | 低效 O (n) |
头部插入 / 删除 | 低效 O (n) | 高效 O (1) |
中间插入 / 删除 | 低效 O (n) | 高效 O (1) |
尾部插入 | 高效 O (1) (均摊) | 高效 O (1) |
假设我们要管理一个班级的学生名单,经常需要进行以下操作:
以下是使用 ArrayList 和 LinkedList 管理学生名单的示例代码:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
// 学生类
class Student {
private int id;
private String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Student{id=" + id + ", name='" + name + "'}";
}
}
public class StudentListManager {
public static void main(String[] args) {
// 使用 ArrayList 管理学生名单
List arrayListStudents = new ArrayList<>();
// 添加学生
arrayListStudents.add(new Student(1, "张三"));
arrayListStudents.add(new Student(2, "李四"));
arrayListStudents.add(new Student(3, "王五"));
// 快速随机访问学生
System.out.println("ArrayList 随机访问:" + arrayListStudents.get(1));
// 中间插入转学生(效率较低)
long startTime = System.nanoTime();
arrayListStudents.add(1, new Student(4, "赵六"));
long endTime = System.nanoTime();
System.out.println("ArrayList 中间插入耗时:" + (endTime - startTime) + " 纳秒");
// 使用 LinkedList 管理学生名单
List linkedListStudents = new LinkedList<>();
// 添加学生
linkedListStudents.add(new Student(1, "张三"));
linkedListStudents.add(new Student(2, "李四"));
linkedListStudents.add(new Student(3, "王五"));
// 中间插入转学生(效率较高)
startTime = System.nanoTime();
((LinkedList) linkedListStudents).add(1, new Student(4, "赵六"));
endTime = System.nanoTime();
System.out.println("LinkedList 中间插入耗时:" + (endTime - startTime) + " 纳秒");
}
}
操作类型 | HashSet | TreeSet |
---|---|---|
添加(add) | 高效 O (1)(均摊) | 高效 O (log n) |
查找(contains) | 高效 O (1)(均摊) | 高效 O (log n) |
遍历 | 无序遍历 | 有序遍历 O (n) |
现在我们要为一个社交应用存储用户的兴趣标签,不同的业务场景对集合有不同的需求:
以下是使用 HashSet 和 TreeSet 管理用户兴趣标签的示例代码:
import java.util.*;
public class InterestTagManager {
public static void main(String[] args) {
// 使用 HashSet 管理兴趣标签(无序、快速查找)
Set hashSetTags = new HashSet<>();
// 添加标签
hashSetTags.add("Java");
hashSetTags.add("Python");
hashSetTags.add("C++");
// 检查标签是否存在
System.out.println("HashSet 中是否存在 Java 标签:" + hashSetTags.contains("Java"));
// 使用 TreeSet 管理兴趣标签(有序、自动排序)
Set treeSetTags = new TreeSet<>();
// 添加标签
treeSetTags.add("Java");
treeSetTags.add("Python");
treeSetTags.add("C++");
// 遍历有序标签
System.out.println("TreeSet 有序遍历:");
for (String tag : treeSetTags) {
System.out.println(tag);
}
// 使用 TreeSet 自定义排序(按标签长度排序)
Set customSortedTags = new TreeSet<>(Comparator.comparingInt(String::length));
customSortedTags.add("Java");
customSortedTags.add("Python");
customSortedTags.add("C++");
System.out.println("按长度排序的 TreeSet:");
for (String tag : customSortedTags) {
System.out.println(tag);
}
}
}
操作类型 | HashMap | TreeMap |
---|---|---|
插入(put) | 高效 O (1)(均摊) | 高效 O (log n) |
查找(get) | 高效 O (1)(均摊) | 高效 O (log n) |
按顺序遍历键 | 无序遍历 | 有序遍历 O (n) |
范围查询(如获取大于某个键的所有键值对) | 不支持高效范围查询 | 支持高效 O (log n + k),k 为范围大小 |
在开发一个学生成绩管理系统时,我们需要根据不同的需求选择合适的 Map:
以下是使用 HashMap 和 TreeMap 管理学生成绩的示例代码:
import java.util.*;
public class GradeManager {
public static void main(String[] args) {
// 使用 HashMap 管理学生成绩(无序、快速存取)
Map hashMapGrades = new HashMap<>();
// 添加成绩
hashMapGrades.put("001", 90);
hashMapGrades.put("002", 85);
hashMapGrades.put("003", 95);
// 快速查询成绩
System.out.println("学号 002 的成绩:" + hashMapGrades.get("002"));
// 使用 TreeMap 管理学生成绩(有序、按学号排序)
Map treeMapGrades = new TreeMap<>();
// 添加成绩(故意乱序)
treeMapGrades.put("003", 95);
treeMapGrades.put("001", 90);
treeMapGrades.put("002", 85);
// 按学号顺序遍历成绩
System.out.println("按学号排序的成绩:");
for (Map.Entry entry : treeMapGrades.entrySet()) {
System.out.println("学号:" + entry.getKey() + ",成绩:" + entry.getValue());
}
// TreeMap 范围查询(获取学号大于等于 002 的学生)
System.out.println("学号大于等于 002 的学生:");
SortedMap tailMap = ((TreeMap) treeMapGrades).tailMap("002");
for (Map.Entry entry : tailMap.entrySet()) {
System.out.println("学号:" + entry.getKey() + ",成绩:" + entry.getValue());
}
}
}
通过深入理解不同集合类的底层原理和性能差异,结合具体的业务场景,我们能够更加精准地选择合适的集合,提高代码的效率和可读性。