《Java 集合框架全解析!从入门到实战,面试 / 开发都用得上!》
第五章:Java集合框架
5.1 集合接口与实现类概述
5.1.1 集合框架体系结构
Java集合框架主要包含两种类型的容器:
- Collection:存储单个元素的集合
- Map:存储键值对的映射
// 集合框架主要接口关系
Collection
├── List
├── Set
└── QueueMap
├── HashMap
├── TreeMap
└── LinkedHashMap
5.1.2 核心接口介绍
import java.util.*;public class CollectionOverview {public static void main(String[] args) {// Collection接口的基本方法演示Collection<String> collection = new ArrayList<>();// 添加元素collection.add("Java");collection.add("Python");collection.add("C++");// 检查包含System.out.println("包含Java: " + collection.contains("Java"));// 遍历集合for (String language : collection) {System.out.println(language);}// 移除元素collection.remove("C++");System.out.println("移除后: " + collection);}
}
5.2 List、Set、Map的核心区别与使用场景
5.2.1 三大集合类型对比
特性 | List | Set | Map |
---|---|---|---|
元素顺序 | 有序 | 无序(LinkedHashSet有序) | 无序(LinkedHashMap有序) |
元素唯一性 | 可重复 | 唯一 | 键唯一,值可重复 |
实现类 | ArrayList, LinkedList | HashSet, TreeSet | HashMap, TreeMap |
访问方式 | 索引访问 | 迭代器访问 | 键访问 |
5.2.2 使用场景分析
public class CollectionScenarios {// List使用场景:需要保持插入顺序,允许重复public static void listScenario() {List<String> studentNames = new ArrayList<>();studentNames.add("张三");studentNames.add("李四");studentNames.add("张三"); // 允许重复// 按索引访问System.out.println("第二个学生: " + studentNames.get(1));}// Set使用场景:需要元素唯一性,不关心顺序public static void setScenario() {Set<String> uniqueIds = new HashSet<>();uniqueIds.add("001");uniqueIds.add("002");uniqueIds.add("001"); // 重复元素不会被添加System.out.println("唯一ID集合: " + uniqueIds);}// Map使用场景:键值对映射关系public static void mapScenario() {Map<String, Integer> studentScores = new HashMap<>();studentScores.put("张三", 85);studentScores.put("李四", 92);studentScores.put("王五", 78);// 通过键快速查找值System.out.println("张三的分数: " + studentScores.get("张三"));}
}
5.3 ArrayList、LinkedList、HashSet、HashMap等集合操作
5.3.1 ArrayList详解
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;public class ArrayListDemo {public static void main(String[] args) {// 创建ArrayListArrayList<String> list = new ArrayList<>();// 添加元素list.add("Apple");list.add("Banana");list.add("Orange");list.add(1, "Grape"); // 在指定位置插入// 访问元素System.out.println("第一个元素: " + list.get(0));System.out.println("列表大小: " + list.size());// 修改元素list.set(2, "Mango");// 删除元素list.remove("Apple");list.remove(0);// 排序list.add("Cherry");list.add("Blueberry");Collections.sort(list);System.out.println("排序后: " + list);// 自定义排序Collections.sort(list, Comparator.reverseOrder());System.out.println("逆序: " + list);// 转换为数组String[] array = list.toArray(new String[0]);// 清空列表list.clear();System.out.println("清空后是否为空: " + list.isEmpty());}
}
5.3.2 LinkedList详解
import java.util.LinkedList;public class LinkedListDemo {public static void main(String[] args) {LinkedList<String> linkedList = new LinkedList<>();// 添加元素linkedList.add("First");linkedList.add("Second");linkedList.addFirst("Head"); // 添加到头部linkedList.addLast("Tail"); // 添加到尾部System.out.println("链表: " + linkedList);// 队列操作linkedList.offer("QueueElement"); // 添加到尾部System.out.println("队首: " + linkedList.peek());System.out.println("出队: " + linkedList.poll());// 栈操作linkedList.push("StackElement"); // 压栈System.out.println("栈顶: " + linkedList.peek());System.out.println("出栈: " + linkedList.pop());System.out.println("最终链表: " + linkedList);}
}
5.3.3 HashSet详解
import java.util.HashSet;
import java.util.Arrays;public class HashSetDemo {public static void main(String[] args) {HashSet<String> set = new HashSet<>();// 添加元素set.add("Java");set.add("Python");set.add("C++");set.add("Java"); // 重复元素,不会被添加System.out.println("集合: " + set);System.out.println("集合大小: " + set.size());// 检查包含System.out.println("包含Java: " + set.contains("Java"));// 移除元素set.remove("C++");// 遍历集合for (String element : set) {System.out.println(element);}// 集合运算HashSet<String> otherSet = new HashSet<>(Arrays.asList("Java", "JavaScript", "Go"));// 并集HashSet<String> union = new HashSet<>(set);union.addAll(otherSet);System.out.println("并集: " + union);// 交集HashSet<String> intersection = new HashSet<>(set);intersection.retainAll(otherSet);System.out.println("交集: " + intersection);// 差集HashSet<String> difference = new HashSet<>(set);difference.removeAll(otherSet);System.out.println("差集: " + difference);}
}
5.3.4 HashMap详解
import java.util.HashMap;
import java.util.Map;public class HashMapDemo {public static void main(String[] args) {// 创建HashMapHashMap<String, Integer> map = new HashMap<>();// 添加键值对map.put("Apple", 10);map.put("Banana", 20);map.put("Orange", 15);map.put("Apple", 25); // 更新已存在的键的值System.out.println("HashMap: " + map);// 访问值System.out.println("Apple的数量: " + map.get("Apple"));System.out.println("获取或默认值: " + map.getOrDefault("Grape", 0));// 检查键值存在System.out.println("包含键Banana: " + map.containsKey("Banana"));System.out.println("包含值100: " + map.containsValue(100));// 遍历HashMapSystem.out.println("=== 遍历方式 ===");// 1. 遍历键for (String key : map.keySet()) {System.out.println("Key: " + key + ", Value: " + map.get(key));}// 2. 遍历值for (Integer value : map.values()) {System.out.println("Value: " + value);}// 3. 遍历键值对for (Map.Entry<String, Integer> entry : map.entrySet()) {System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());}// 4. forEach方法map.forEach((key, value) -> System.out.println("Key: " + key + ", Value: " + value));// 移除元素map.remove("Banana");System.out.println("移除后: " + map);// 替换值map.replace("Apple", 30);System.out.println("替换后: " + map);}
}
5.4 迭代器(Iterator)与集合遍历
5.4.1 迭代器基本使用
import java.util.*;public class IteratorDemo {public static void main(String[] args) {List<String> list = Arrays.asList("Java", "Python", "C++", "JavaScript");// 获取迭代器Iterator<String> iterator = list.iterator();// 遍历集合while (iterator.hasNext()) {String element = iterator.next();System.out.println(element);// 安全地移除元素if ("C++".equals(element)) {iterator.remove(); // 在ListIterator中可用}}}
}
5.4.2 ListIterator双向遍历
import java.util.*;public class ListIteratorDemo {public static void main(String[] args) {List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D"));// 获取ListIteratorListIterator<String> listIterator = list.listIterator();System.out.println("正向遍历:");while (listIterator.hasNext()) {int index = listIterator.nextIndex();String element = listIterator.next();System.out.println("Index: " + index + ", Element: " + element);}System.out.println("\n反向遍历:");while (listIterator.hasPrevious()) {int index = listIterator.previousIndex();String element = listIterator.previous();System.out.println("Index: " + index + ", Element: " + element);}// 修改元素listIterator = list.listIterator();if (listIterator.hasNext()) {listIterator.next();listIterator.set("Modified-A"); // 修改当前元素}System.out.println("修改后: " + list);}
}
5.4.3 增强for循环与迭代器
import java.util.*;public class EnhancedForLoop {public static void main(String[] args) {List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);// 增强for循环(底层使用迭代器)System.out.println("增强for循环:");for (Integer num : numbers) {System.out.println(num);}// 等效的迭代器写法System.out.println("\n迭代器写法:");for (Iterator<Integer> it = numbers.iterator(); it.hasNext();) {Integer num = it.next();System.out.println(num);}// 在遍历时修改集合的注意事项List<String> names = new ArrayList<>(Arrays.asList("Tom", "Jerry", "Mike"));// 错误的方式:在增强for循环中修改集合// for (String name : names) {// if ("Jerry".equals(name)) {// names.remove(name); // 会抛出ConcurrentModificationException// }// }// 正确的方式:使用迭代器的remove方法Iterator<String> iterator = names.iterator();while (iterator.hasNext()) {String name = iterator.next();if ("Jerry".equals(name)) {iterator.remove(); // 安全移除}}System.out.println("安全移除后: " + names);}
}
5.5 泛型(Generics)与类型安全
5.5.1 泛型基本概念
import java.util.*;// 自定义泛型类
class GenericBox<T> {private T content;public void setContent(T content) {this.content = content;}public T getContent() {return content;}
}public class GenericsDemo {public static void main(String[] args) {// 不使用泛型的问题List rawList = new ArrayList(); // 原始类型rawList.add("String");rawList.add(123); // 编译时不会报错// 运行时可能抛出ClassCastException// String str = (String) rawList.get(1); // 错误!// 使用泛型保证类型安全List<String> stringList = new ArrayList<>();stringList.add("Hello");// stringList.add(123); // 编译错误!String str = stringList.get(0); // 不需要强制类型转换// 自定义泛型类的使用GenericBox<String> stringBox = new GenericBox<>();stringBox.setContent("Generic String");String content = stringBox.getContent(); // 自动类型转换GenericBox<Integer> integerBox = new GenericBox<>();integerBox.setContent(100);int number = integerBox.getContent();System.out.println("字符串内容: " + content);System.out.println("数字内容: " + number);}
}
5.5.2 泛型方法
import java.util.*;public class GenericMethods {// 泛型方法public static <T> void printArray(T[] array) {for (T element : array) {System.out.print(element + " ");}System.out.println();}// 有界类型参数的泛型方法public static <T extends Comparable<T>> T findMax(T[] array) {if (array == null || array.length == 0) {return null;}T max = array[0];for (T element : array) {if (element.compareTo(max) > 0) {max = element;}}return max;}// 通配符使用public static void processList(List<? extends Number> list) {for (Number number : list) {System.out.println(number.doubleValue());}}public static void main(String[] args) {// 测试泛型方法Integer[] intArray = {1, 2, 3, 4, 5};String[] strArray = {"Apple", "Banana", "Orange"};System.out.println("整数数组:");printArray(intArray);System.out.println("字符串数组:");printArray(strArray);// 测试有界泛型方法Integer maxInt = findMax(intArray);System.out.println("最大整数: " + maxInt);// 测试通配符List<Integer> integerList = Arrays.asList(1, 2, 3);List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3);System.out.println("处理整数列表:");processList(integerList);System.out.println("处理双精度列表:");processList(doubleList);}
}
5.5.3 类型安全的集合操作
import java.util.*;public class TypeSafeCollections {// 类型安全的集合创建public static void typeSafeDemo() {// 传统方式 - 可能产生类型不安全List unsafeList = new ArrayList();unsafeList.add("String");unsafeList.add(123); // 编译时不报错// 泛型方式 - 类型安全List<String> safeList = new ArrayList<>();safeList.add("String");// safeList.add(123); // 编译错误!// 从安全集合获取元素不需要类型转换String element = safeList.get(0);}// 泛型与集合框架的结合public static void genericCollections() {// 类型安全的MapMap<String, List<Integer>> studentScores = new HashMap<>();// 添加数据studentScores.put("张三", Arrays.asList(85, 90, 78));studentScores.put("李四", Arrays.asList(92, 88, 95));// 类型安全的访问List<Integer> scores = studentScores.get("张三");int firstScore = scores.get(0); // 自动拆箱,不需要强制转换System.out.println("张三的第一个分数: " + firstScore);// 遍历类型安全的Mapfor (Map.Entry<String, List<Integer>> entry : studentScores.entrySet()) {String name = entry.getKey();List<Integer> scoreList = entry.getValue();System.out.println(name + "的分数: " + scoreList);}}// 使用Collections工具类进行类型安全操作public static void collectionsUtility() {List<String> list = new ArrayList<>();// 添加多个元素Collections.addAll(list, "A", "B", "C", "D");// 类型安全的复制List<String> dest = new ArrayList<>(Arrays.asList(new String[list.size()]));Collections.copy(dest, list);System.out.println("复制后的列表: " + dest);// 类型安全的不可修改视图List<String> unmodifiableList = Collections.unmodifiableList(list);// unmodifiableList.add("E"); // 运行时抛出UnsupportedOperationException}public static void main(String[] args) {typeSafeDemo();genericCollections();collectionsUtility();}
}
5.5.4 实际应用示例
import java.util.*;// 学生类
class Student implements Comparable<Student> {private String name;private int score;public Student(String name, int score) {this.name = name;this.score = score;}public String getName() { return name; }public int getScore() { return score; }@Overridepublic int compareTo(Student other) {return Integer.compare(this.score, other.score);}@Overridepublic String toString() {return name + "(" + score + ")";}
}public class PracticalExample {// 使用泛型方法对学生列表进行排序public static <T extends Comparable<T>> void sortStudents(List<T> list) {Collections.sort(list);}// 查找最高分学生public static Student findTopStudent(List<Student> students) {return Collections.max(students);}// 统计分数分布public static Map<String, List<Student>> groupByScoreRange(List<Student> students) {Map<String, List<Student>> result = new HashMap<>();result.put("优秀(90-100)", new ArrayList<>());result.put("良好(80-89)", new ArrayList<>());result.put("及格(60-79)", new ArrayList<>());result.put("不及格(0-59)", new ArrayList<>());for (Student student : students) {int score = student.getScore();if (score >= 90) {result.get("优秀(90-100)").add(student);} else if (score >= 80) {result.get("良好(80-89)").add(student);} else if (score >= 60) {result.get("及格(60-79)").add(student);} else {result.get("不及格(0-59)").add(student);}}return result;}public static void main(String[] args) {// 创建学生列表List<Student> students = Arrays.asList(new Student("张三", 85),new Student("李四", 92),new Student("王五", 78),new Student("赵六", 65),new Student("钱七", 95));// 排序System.out.println("排序前: " + students);sortStudents(students);System.out.println("排序后: " + students);// 查找最高分Student topStudent = findTopStudent(students);System.out.println("最高分学生: " + topStudent);// 分组统计Map<String, List<Student>> scoreGroups = groupByScoreRange(students);System.out.println("\n分数分布:");for (Map.Entry<String, List<Student>> entry : scoreGroups.entrySet()) {System.out.println(entry.getKey() + ": " + entry.getValue());}}
}
总结
Java集合框架提供了强大而灵活的数据结构处理能力:
- List:有序、可重复的集合,适合需要保持插入顺序或按索引访问的场景
- Set:无序、唯一的集合,适合需要元素唯一性的场景
- Map:键值对映射,适合需要通过键快速查找值的场景
- 迭代器:提供了统一的集合遍历方式,支持安全的元素移除
- 泛型:保证了编译时的类型安全,避免了运行时类型转换异常
掌握这些核心概念和用法,能够帮助开发者编写出更加健壮、可维护的Java代码。