Appearance
集合框架
Java 集合框架提供了一套性能优良、使用方便的接口和类,用于存储和操作对象集合。
集合框架概述
集合体系结构
text
┌─────────────────────────────────────────────────────────────────┐
│ Java 集合框架 │
├─────────────────────────────────────────────────────────────────┤
│ Iterable │
│ │ │
│ Collection │
│ / | \ │
│ List Set Queue │
│ / \ | | │
│ ArrayList HashSet LinkedList │
│ LinkedList TreeSet PriorityQueue │
│ Vector LinkedHashSet │
│ │
│ Map(独立接口) │
│ / | \ │
│ HashMap TreeMap LinkedHashMap │
│ Hashtable │
└─────────────────────────────────────────────────────────────────┘集合分类
| 类型 | 特点 | 主要实现类 |
|---|---|---|
| List | 有序、可重复 | ArrayList, LinkedList, Vector |
| Set | 无序、不可重复 | HashSet, TreeSet, LinkedHashSet |
| Map | 键值对、键唯一 | HashMap, TreeMap, LinkedHashMap |
| Queue | 先进先出 | LinkedList, PriorityQueue |
Collection 接口
Collection 是单值集合的根接口。
常用方法
java
import java.util.*;
public class CollectionMethods {
public static void main(String[] args) {
Collection<String> collection = new ArrayList<>();
// 添加元素
collection.add("张三");
collection.add("李四");
collection.add("王五");
System.out.println("添加后:" + collection);
// 添加多个元素
collection.addAll(Arrays.asList("赵六", "钱七"));
System.out.println("添加多个后:" + collection);
// 判断是否包含
System.out.println("包含张三:" + collection.contains("张三"));
System.out.println("包含所有:" + collection.containsAll(Arrays.asList("张三", "李四")));
// 大小和判空
System.out.println("大小:" + collection.size());
System.out.println("是否为空:" + collection.isEmpty());
// 删除元素
collection.remove("张三");
System.out.println("删除张三后:" + collection);
// 遍历
System.out.println("\n遍历方式一:增强 for");
for (String name : collection) {
System.out.println(name);
}
System.out.println("\n遍历方式二:Iterator");
Iterator<String> iterator = collection.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
System.out.println("\n遍历方式三:forEach + Lambda");
collection.forEach(System.out::println);
// 清空
collection.clear();
System.out.println("清空后:" + collection);
}
}List 接口
List 是有序集合,可以存储重复元素,可以通过索引访问。
ArrayList
ArrayList 基于动态数组实现,查询快,增删慢。
java
import java.util.*;
public class ArrayListDemo {
public static void main(String[] args) {
// 创建 ArrayList
List<String> list = new ArrayList<>();
// 添加元素
list.add("Java");
list.add("Python");
list.add("C++");
list.add("JavaScript");
System.out.println("初始列表:" + list);
// 在指定位置插入
list.add(1, "Go");
System.out.println("插入后:" + list);
// 获取元素
System.out.println("索引0的元素:" + list.get(0));
// 修改元素
list.set(0, "Java SE");
System.out.println("修改后:" + list);
// 查找元素
System.out.println("Python 的索引:" + list.indexOf("Python"));
System.out.println("最后出现的位置:" + list.lastIndexOf("Python"));
// 截取子列表
List<String> subList = list.subList(1, 3);
System.out.println("子列表:" + subList);
// 排序
list.sort(String::compareTo);
System.out.println("排序后:" + list);
// 遍历方式
System.out.println("\n使用普通 for 循环:");
for (int i = 0; i < list.size(); i++) {
System.out.println(i + " -> " + list.get(i));
}
System.out.println("\n使用 ListIterator(双向遍历):");
ListIterator<String> listIterator = list.listIterator(list.size());
while (listIterator.hasPrevious()) {
System.out.println(listIterator.previousIndex() + " -> " + listIterator.previous());
}
}
}LinkedList
LinkedList 基于双向链表实现,增删快,查询慢。
java
import java.util.*;
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
// 添加元素
list.add("A");
list.add("B");
list.add("C");
System.out.println("初始列表:" + list);
// 在头部添加
list.addFirst("First");
System.out.println("头部添加后:" + list);
// 在尾部添加
list.addLast("Last");
System.out.println("尾部添加后:" + list);
// 获取头部和尾部
System.out.println("头部元素:" + list.getFirst());
System.out.println("尾部元素:" + list.getLast());
// 删除头部和尾部
list.removeFirst();
list.removeLast();
System.out.println("删除头尾后:" + list);
// 栈操作(后进先出)
list.push("X"); // 等同于 addFirst
list.push("Y");
System.out.println("push 后:" + list);
System.out.println("pop:" + list.pop()); // 等同于 removeFirst
System.out.println("pop 后:" + list);
// 队列操作(先进先出)
LinkedList<String> queue = new LinkedList<>();
queue.offer("1"); // 添加到尾部
queue.offer("2");
queue.offer("3");
System.out.println("\n队列:" + queue);
System.out.println("poll:" + queue.poll()); // 从头部取出
System.out.println("poll 后:" + queue);
}
}ArrayList vs LinkedList
text
┌─────────────────────────────────────────────────────────────────┐
│ ArrayList vs LinkedList │
├─────────────────────────────────────────────────────────────────┤
│ 操作 │ ArrayList │ LinkedList │
├─────────────────────────────────────────────────────────────────┤
│ 随机访问 │ O(1) │ O(n) │
│ 头部插入 │ O(n) │ O(1) │
│ 尾部插入 │ O(1) │ O(1) │
│ 中间插入 │ O(n) │ O(n) │
│ 内存占用 │ 较小 │ 较大 │
│ 适用场景 │ 查询多 │ 增删多 │
└─────────────────────────────────────────────────────────────────┘Set 接口
Set 是不包含重复元素的集合。
HashSet
HashSet 基于哈希表实现,元素无序,查询效率高。
java
import java.util.*;
public class HashSetDemo {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
// 添加元素
set.add("Java");
set.add("Python");
set.add("C++");
set.add("Java"); // 重复元素不会被添加
System.out.println("HashSet:" + set); // 顺序不确定
// 判断包含
System.out.println("包含 Java:" + set.contains("Java"));
// 删除元素
set.remove("C++");
System.out.println("删除后:" + set);
// 遍历
System.out.println("\n遍历:");
for (String item : set) {
System.out.println(item);
}
// 集合操作
Set<String> set1 = new HashSet<>(Arrays.asList("A", "B", "C"));
Set<String> set2 = new HashSet<>(Arrays.asList("B", "C", "D"));
// 并集
Set<String> union = new HashSet<>(set1);
union.addAll(set2);
System.out.println("\n并集:" + union);
// 交集
Set<String> intersection = new HashSet<>(set1);
intersection.retainAll(set2);
System.out.println("交集:" + intersection);
// 差集
Set<String> difference = new HashSet<>(set1);
difference.removeAll(set2);
System.out.println("差集:" + difference);
}
}LinkedHashSet
LinkedHashSet 维护元素的插入顺序。
java
import java.util.*;
public class LinkedHashSetDemo {
public static void main(String[] args) {
// LinkedHashSet:维护插入顺序
Set<String> linkedSet = new LinkedHashSet<>();
linkedSet.add("C");
linkedSet.add("A");
linkedSet.add("B");
System.out.println("LinkedHashSet:" + linkedSet); // [C, A, B]
// HashSet:不保证顺序
Set<String> hashSet = new HashSet<>();
hashSet.add("C");
hashSet.add("A");
hashSet.add("B");
System.out.println("HashSet:" + hashSet); // 顺序不确定
}
}TreeSet
TreeSet 基于红黑树实现,元素有序(自然排序或自定义排序)。
java
import java.util.*;
public class TreeSetDemo {
public static void main(String[] args) {
// 自然排序
TreeSet<Integer> numbers = new TreeSet<>();
numbers.add(5);
numbers.add(2);
numbers.add(8);
numbers.add(1);
System.out.println("自然排序:" + numbers); // [1, 2, 5, 8]
// 特定方法
System.out.println("第一个元素:" + numbers.first());
System.out.println("最后一个元素:" + numbers.last());
System.out.println("小于5的最大元素:" + numbers.lower(5));
System.out.println("大于5的最小元素:" + numbers.higher(5));
// 范围操作
System.out.println("小于等于5的元素:" + numbers.headSet(5, true));
System.out.println("大于等于2的元素:" + numbers.tailSet(2));
System.out.println("2到5之间的元素:" + numbers.subSet(2, 5));
// 自定义排序(降序)
TreeSet<Integer> descending = new TreeSet<>(Comparator.reverseOrder());
descending.addAll(numbers);
System.out.println("降序排序:" + descending);
// 自定义对象排序
TreeSet<Person> people = new TreeSet<>((p1, p2) -> p1.age - p2.age);
people.add(new Person("张三", 25));
people.add(new Person("李四", 20));
people.add(new Person("王五", 30));
System.out.println("\n按年龄排序:");
people.forEach(p -> System.out.println(p.name + " - " + p.age));
}
}
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}Map 接口
Map 存储键值对,键唯一,值可重复。
HashMap
HashMap 基于哈希表实现,键值对无序,查询效率高。
java
import java.util.*;
public class HashMapDemo {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
// 添加键值对
map.put("张三", 25);
map.put("李四", 30);
map.put("王五", 28);
System.out.println("初始 Map:" + map);
// 获取值
System.out.println("张三的年龄:" + map.get("张三"));
System.out.println("不存在的键:" + map.get("赵六")); // null
System.out.println("不存在返回默认值:" + map.getOrDefault("赵六", 0));
// 判断包含
System.out.println("包含张三键:" + map.containsKey("张三"));
System.out.println("包含25值:" + map.containsValue(25));
// 修改值
map.put("张三", 26); // 键相同会覆盖
System.out.println("修改后:" + map);
// 如果键不存在才添加
map.putIfAbsent("张三", 27); // 不会添加
map.putIfAbsent("赵六", 22); // 会添加
System.out.println("putIfAbsent 后:" + map);
// 删除
map.remove("赵六");
System.out.println("删除后:" + map);
// 遍历方式
System.out.println("\n遍历方式一:遍历键");
for (String key : map.keySet()) {
System.out.println(key + " -> " + map.get(key));
}
System.out.println("\n遍历方式二:遍历值");
for (Integer value : map.values()) {
System.out.println(value);
}
System.out.println("\n遍历方式三:遍历键值对");
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
System.out.println("\n遍历方式四:forEach");
map.forEach((k, v) -> System.out.println(k + " -> " + v));
// 计算方法
map.merge("张三", 1, Integer::sum); // 如果存在则合并
System.out.println("\nmerge 后:" + map);
map.compute("李四", (k, v) -> v + 1); // 计算新值
System.out.println("compute 后:" + map);
}
}LinkedHashMap
LinkedHashMap 维护键值对的插入顺序或访问顺序。
java
import java.util.*;
public class LinkedHashMapDemo {
public static void main(String[] args) {
// 插入顺序
Map<String, Integer> insertOrder = new LinkedHashMap<>();
insertOrder.put("C", 3);
insertOrder.put("A", 1);
insertOrder.put("B", 2);
System.out.println("插入顺序:" + insertOrder);
// 访问顺序(可用于实现 LRU 缓存)
Map<String, Integer> accessOrder = new LinkedHashMap<>(16, 0.75f, true);
accessOrder.put("A", 1);
accessOrder.put("B", 2);
accessOrder.put("C", 3);
System.out.println("初始:" + accessOrder);
accessOrder.get("A"); // 访问 A
accessOrder.get("B"); // 访问 B
System.out.println("访问后:" + accessOrder); // A 和 B 移到最后
}
}TreeMap
TreeMap 基于红黑树实现,键有序。
java
import java.util.*;
public class TreeMapDemo {
public static void main(String[] args) {
// 自然排序
TreeMap<String, Integer> map = new TreeMap<>();
map.put("C", 3);
map.put("A", 1);
map.put("B", 2);
System.out.println("TreeMap:" + map); // 按键排序
// 范围操作
System.out.println("第一个键:" + map.firstKey());
System.out.println("最后一个键:" + map.lastKey());
System.out.println("小于B的键值对:" + map.headMap("B"));
System.out.println("大于等于B的键值对:" + map.tailMap("B"));
System.out.println("A到C之间的键值对:" + map.subMap("A", "C"));
}
}Collections 工具类
Collections 提供了操作集合的静态方法。
java
import java.util.*;
public class CollectionsDemo {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>(Arrays.asList(5, 2, 8, 1, 9, 3));
// 排序
Collections.sort(list);
System.out.println("升序排序:" + list);
Collections.sort(list, Comparator.reverseOrder());
System.out.println("降序排序:" + list);
// 二分查找(需要先排序)
Collections.sort(list);
int index = Collections.binarySearch(list, 5);
System.out.println("5 的索引:" + index);
// 最大最小值
System.out.println("最大值:" + Collections.max(list));
System.out.println("最小值:" + Collections.min(list));
// 反转
Collections.reverse(list);
System.out.println("反转后:" + list);
// 打乱
Collections.shuffle(list);
System.out.println("打乱后:" + list);
// 填充
List<String> names = new ArrayList<>(Arrays.asList("A", "B", "C"));
Collections.fill(names, "X");
System.out.println("填充后:" + names);
// 复制
List<String> dest = Arrays.asList(new String[3]);
List<String> src = Arrays.asList("1", "2", "3");
Collections.copy(dest, src);
System.out.println("复制后:" + dest);
// 不可变集合
List<String> immutable = Collections.unmodifiableList(Arrays.asList("A", "B"));
System.out.println("不可变集合:" + immutable);
// immutable.add("C"); // UnsupportedOperationException
// 同步集合(线程安全)
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
Set<String> syncSet = Collections.synchronizedSet(new HashSet<>());
Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<>());
// 空集合
List<String> emptyList = Collections.emptyList();
Set<String> emptySet = Collections.emptySet();
Map<String, String> emptyMap = Collections.emptyMap();
// 单元素集合
List<String> singletonList = Collections.singletonList("Only");
Set<String> singletonSet = Collections.singleton("Only");
}
}集合选择
text
┌─────────────────────────────────────────────────────────────────┐
│ 集合选择指南 │
├─────────────────────────────────────────────────────────────────┤
│ 需要快速随机访问元素? │
│ 是 → ArrayList │
│ 否 → 需要频繁在头部插入删除? │
│ 是 → LinkedList │
│ 否 → ArrayList │
│ │
│ 需要存储不重复元素? │
│ 是 → 需要排序? │
│ 是 → TreeSet │
│ 否 → 需要保持插入顺序? │
│ 是 → LinkedHashSet │
│ 否 → HashSet │
│ │
│ 需要键值对存储? │
│ 是 → 需要按键排序? │
│ 是 → TreeMap │
│ 否 → 需要保持插入顺序? │
│ 是 → LinkedHashMap │
│ 否 → HashMap │
└─────────────────────────────────────────────────────────────────┘小结
本章我们学习了:
- Collection 接口:单值集合的根接口
- List 接口:有序可重复,ArrayList、LinkedList
- Set 接口:无序不可重复,HashSet、TreeSet、LinkedHashSet
- Map 接口:键值对,HashMap、TreeMap、LinkedHashMap
- Collections 工具类:排序、查找、同步等操作
下一章,我们将学习 IO流,了解 Java 的输入输出操作。
