跳到主要内容

Java 集合框架概览

Java 集合框架(Collections Framework)是 Java 中用于存储和操作对象组的统一架构。理解集合框架的层次结构和各类集合的特点,是高效使用 Java 集合的基础。本章将详细介绍 Java 集合框架的整体结构。

Collection 与 Map 层次结构

集合框架的层次结构

Java 集合框架主要分为两个接口体系:

  1. Collection 接口:存储单个元素的集合
  2. Map 接口:存储键值对的映射

Collection 接口层次

Collection
├── List(有序、可重复)
│ ├── ArrayList
│ ├── LinkedList
│ └── Vector(已过时)
├── Set(无序、不可重复)
│ ├── HashSet
│ ├── LinkedHashSet
│ └── TreeSet
└── Queue(队列)
├── PriorityQueue
└── Deque
└── ArrayDeque

Map 接口层次

Map
├── HashMap
├── LinkedHashMap
├── TreeMap
└── Hashtable(已过时)

核心接口说明

Collection 接口

所有集合类的根接口,定义了集合的基本操作:

public interface Collection<E> {
// 基本操作
boolean add(E e);
boolean remove(Object o);
boolean contains(Object o);
int size();
boolean isEmpty();
void clear();

// 批量操作
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
boolean retainAll(Collection<?> c);

// 遍历操作
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
}

Map 接口

存储键值对的接口

public interface Map<K, V> {
// 基本操作
V put(K key, V value);
V get(Object key);
V remove(Object key);
boolean containsKey(Object key);
boolean containsValue(Object value);
int size();
boolean isEmpty();
void clear();

// 视图操作
Set<K> keySet();
Collection<V> values();
Set<Map.Entry<K, V>> entrySet();
}

List / Set / Map / Queue 区别与特点

List(列表)

特点

  • 有序:元素按照插入顺序存储
  • 可重复:允许存储相同的元素
  • 有索引:可以通过索引访问元素

实现类

  • ArrayList:基于数组,随机访问快,插入删除慢
  • LinkedList:基于链表,插入删除快,随机访问慢
List<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");
list.add("apple"); // 可以重复
System.out.println(list.get(0)); // "apple"(有索引)

Set(集合)

特点

  • 无序:元素没有固定顺序(TreeSet 除外)
  • 不可重复:不允许存储相同的元素
  • 无索引:不能通过索引访问

实现类

  • HashSet:基于哈希表,查找快,无序
  • LinkedHashSet:基于哈希表+链表,保持插入顺序
  • TreeSet:基于红黑树,有序,支持排序
Set<String> set = new HashSet<>();
set.add("apple");
set.add("banana");
set.add("apple"); // 重复元素,不会添加
System.out.println(set.size()); // 2

Map(映射)

特点

  • 键值对:存储 key-value 对
  • 键唯一:每个 key 只能对应一个 value
  • 值可重复:不同的 key 可以对应相同的 value

实现类

  • HashMap:基于哈希表,查找快,无序
  • LinkedHashMap:保持插入顺序
  • TreeMap:基于红黑树,按键排序
Map<String, Integer> map = new HashMap<>();
map.put("apple", 10);
map.put("banana", 20);
map.put("apple", 30); // 覆盖之前的 value
System.out.println(map.get("apple")); // 30

Queue(队列)

特点

  • FIFO:先进先出(First In First Out)
  • 特殊操作:支持队列特有的操作(offer、poll、peek)

实现类

  • LinkedList:可以作为队列使用
  • PriorityQueue:优先级队列,按优先级排序
  • ArrayDeque:双端队列,可以作为栈或队列使用
Queue<String> queue = new LinkedList<>();
queue.offer("first");
queue.offer("second");
System.out.println(queue.poll()); // "first"(先进先出)

案例对比:选择合适集合类型

场景 1:存储学生列表(有序、可重复)

需求:存储学生列表,需要按顺序访问,可能有重复

选择List(ArrayList 或 LinkedList)

List<Student> students = new ArrayList<>();
students.add(new Student("张三", 20));
students.add(new Student("李四", 22));
students.add(new Student("张三", 20)); // 可以重复

// 按顺序访问
for (int i = 0; i < students.size(); i++) {
System.out.println(students.get(i));
}

场景 2:存储唯一标签(无序、不可重复)

需求:存储文章标签,标签不能重复,顺序不重要

选择Set(HashSet)

Set<String> tags = new HashSet<>();
tags.add("Java");
tags.add("Python");
tags.add("Java"); // 不会添加重复标签

System.out.println(tags.size()); // 2

场景 3:存储学生成绩(键值对)

需求:存储学生姓名和成绩的对应关系

选择Map(HashMap)

Map<String, Integer> scores = new HashMap<>();
scores.put("张三", 85);
scores.put("李四", 90);
scores.put("王五", 78);

System.out.println("张三的成绩:" + scores.get("张三")); // 85

场景 4:任务队列(FIFO)

需求:处理任务队列,按顺序执行

选择Queue(LinkedList 或 ArrayDeque)

Queue<Task> tasks = new LinkedList<>();
tasks.offer(new Task("任务1"));
tasks.offer(new Task("任务2"));

while (!tasks.isEmpty()) {
Task task = tasks.poll(); // 按顺序取出
task.execute();
}

场景 5:需要排序的集合

需求:存储学生,按成绩排序

选择TreeSetTreeMap

// 使用 TreeSet(需要实现 Comparable 或提供 Comparator)
TreeSet<Student> students = new TreeSet<>((s1, s2) ->
Integer.compare(s2.getScore(), s1.getScore()));
students.add(new Student("张三", 85));
students.add(new Student("李四", 90));

// 使用 TreeMap(按键排序)
TreeMap<String, Integer> scores = new TreeMap<>();
scores.put("张三", 85);
scores.put("李四", 90);
// 按键的字典序排序

场景 6:需要保持插入顺序

需求:存储访问记录,需要保持访问顺序

选择LinkedHashSetLinkedHashMap

// 保持插入顺序的 Set
LinkedHashSet<String> visited = new LinkedHashSet<>();
visited.add("page1");
visited.add("page2");
visited.add("page3");
// 遍历时保持插入顺序

// 保持插入顺序的 Map
LinkedHashMap<String, Integer> cache = new LinkedHashMap<>();
cache.put("key1", 1);
cache.put("key2", 2);
// 遍历时保持插入顺序

集合选择指南

选择 List 的场景

  • 需要按顺序存储元素
  • 允许重复元素
  • 需要通过索引访问
  • 需要频繁按位置插入/删除(使用 LinkedList)
  • 需要频繁随机访问(使用 ArrayList)

选择 Set 的场景

  • 需要存储唯一元素
  • 不需要顺序(HashSet)
  • 需要保持插入顺序(LinkedHashSet)
  • 需要排序(TreeSet)

选择 Map 的场景

  • 需要键值对映射
  • 需要根据 key 快速查找 value
  • 不需要顺序(HashMap)
  • 需要保持插入顺序(LinkedHashMap)
  • 需要按键排序(TreeMap)

选择 Queue 的场景

  • 需要 FIFO 队列
  • 需要优先级队列(PriorityQueue)
  • 需要双端队列(ArrayDeque)

性能对比

List 实现类性能

操作ArrayListLinkedList
随机访问O(1)O(n)
插入(末尾)O(1)O(1)
插入(中间)O(n)O(n)
删除O(n)O(n)

Set 实现类性能

操作HashSetLinkedHashSetTreeSet
添加O(1)O(1)O(log n)
查找O(1)O(1)O(log n)
删除O(1)O(1)O(log n)
有序插入顺序排序

Map 实现类性能

操作HashMapLinkedHashMapTreeMap
添加O(1)O(1)O(log n)
查找O(1)O(1)O(log n)
删除O(1)O(1)O(log n)
有序插入顺序排序

实际示例

示例 1:综合使用

import java.util.*;

public class CollectionExample {
public static void main(String[] args) {
// List:存储有序列表
List<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");
list.add("apple");
System.out.println("List:" + list);

// Set:存储唯一元素
Set<String> set = new HashSet<>();
set.add("apple");
set.add("banana");
set.add("apple");
System.out.println("Set:" + set);

// Map:存储键值对
Map<String, Integer> map = new HashMap<>();
map.put("apple", 10);
map.put("banana", 20);
System.out.println("Map:" + map);

// Queue:队列
Queue<String> queue = new LinkedList<>();
queue.offer("first");
queue.offer("second");
System.out.println("Queue:" + queue.poll());
}
}

示例 2:选择合适的集合

public class CollectionSelector {
// 场景 1:存储购物车商品(有序、可重复)
public static List<Product> shoppingCart() {
List<Product> cart = new ArrayList<>();
cart.add(new Product("商品1"));
cart.add(new Product("商品2"));
cart.add(new Product("商品1")); // 可以重复
return cart;
}

// 场景 2:存储用户 ID(唯一)
public static Set<String> userIds() {
Set<String> userIds = new HashSet<>();
userIds.add("user1");
userIds.add("user2");
userIds.add("user1"); // 不会重复
return userIds;
}

// 场景 3:存储用户信息(键值对)
public static Map<String, User> userMap() {
Map<String, User> users = new HashMap<>();
users.put("user1", new User("张三"));
users.put("user2", new User("李四"));
return users;
}

// 场景 4:任务队列
public static Queue<Task> taskQueue() {
Queue<Task> tasks = new LinkedList<>();
tasks.offer(new Task("任务1"));
tasks.offer(new Task("任务2"));
return tasks;
}
}

小结

Java 集合框架概览要点:

  • Collection 接口:存储单个元素(List、Set、Queue)
  • Map 接口:存储键值对
  • List:有序、可重复,有索引
  • Set:无序、不可重复,无索引
  • Map:键值对,键唯一
  • Queue:FIFO 队列

关键要点

  • 根据需求选择合适的集合类型
  • 理解各集合的特点和性能
  • List 用于有序可重复的场景
  • Set 用于唯一元素的场景
  • Map 用于键值对映射的场景
  • Queue 用于队列场景

理解了集合框架的概览,你就能选择合适的集合类型。在下一章,我们将学习 Java 的泛型。