教程中心 / Java教程 / 集合简介

集合框架

15分钟 集合框架

引言:什么是集合框架?

Java集合框架(Java Collections Framework)是一套用于存储和操作对象组的统一架构,提供了一套性能优良、使用方便的接口和实现类。

集合类比

想象一个图书馆的藏书系统:

数组:像是一个固定大小的书架
- 书必须按顺序排列
- 书架大小固定,放满了就不能再放新书

集合框架:像是图书馆的智能管理系统
- 有不同类型的书架(List/Set/Queue/Map)
- 可以根据需求自动扩展
- 查找、添加、删除都非常方便

集合框架体系结构

完整继承关系

Iterable<T>
Collection<E>
List<E>
Set<E>
Queue<E>
├─ArrayList
├─LinkedList
├─HashSet
├─TreeSet
Map<K,V>
├─HashMap
├─TreeMap
└─LinkedHashMap

四大接口对比

接口特点元素可重复?元素有序?典型实现
List有序集合✓ 可以✓ 按索引ArrayList, LinkedList
Set不允许重复✗ 不可以✗ 不保证HashSet, TreeSet
Queue先进先出✓ 可以✓ 按插入顺序ArrayDeque, PriorityQueue
Map键值对键不可重复键不保证HashMap, TreeMap

List接口 - 有序集合

List是一个有序、可重复的集合,可以根据索引访问元素。

List特点

  • 元素按插入顺序存储
  • 每个元素都有对应的索引(0, 1, 2...)
  • 可以存储相同元素的多个副本
  • 支持双向访问:按索引或按迭代器

ArrayList vs LinkedList

操作ArrayListLinkedList
按索引访问O(1) 快O(n) 慢
头部插入/删除O(n) 慢O(1) 快
尾部插入/删除均摊O(1) 快O(1) 快
内存占用连续空间,省内存节点分散,占内存多
使用场景频繁随机访问频繁插入/删除

Set接口 - 无重复集合

Set是一个不允许重复元素的集合,适用于去重和查找。

Set实现类对比

实现类底层结构元素有序?Null元素?适用场景
HashSet哈希表不保证允许一个通用场景,高效查找
LinkedHashSet哈希表+链表按插入顺序允许一个需要保持插入顺序
TreeSet红黑树按自然顺序/自定义不允许需要排序的场景

Queue接口 - 队列

Queue是一个先进先出(FIFO)的集合,适用于任务调度、缓冲等场景。

Queue常见操作

Queue queue = new LinkedList<>();

queue.offer("第一个");  // 入队
queue.offer("第二个");
queue.offer("第三个");

String first = queue.poll();  // 出队,返回"第一个"
String peek = queue.peek();   // 查看队首,不移除

Deque - 双端队列

Deque是Queue的子接口,支持两端插入和删除

Deque deque = new ArrayDeque<>();

deque.offerFirst("头部");  // 头部插入
deque.offerLast("尾部");  // 尾部插入

String head = deque.pollFirst();  // 头部取出
String tail = deque.pollLast();   // 尾部取出

Map接口 - 键值对映射

Map存储键值对(Key-Value),键不能重复,每个键对应一个值。

Map类比:字典

Map就像一本字典:

键(Key)        值(Value)
──────        ──────
"apple"    →   "苹果"
"banana"   →   "香蕉"
"orange"   →   "橙子"

特点:
- 键不能重复(一个英文单词只有一个解释)
- 可以通过键快速查找值
- 键值对是一一对应的

Map实现类对比

实现类底层结构键有序?Null键?适用场景
HashMap哈希表不保证允许一个通用场景,高效查找
LinkedHashMap哈希表+链表按插入顺序允许一个需要保持插入顺序
TreeMap红黑树按自然顺序不允许需要按键排序
Hashtable哈希表不保证不允许需要线程安全(旧)

Collection接口核心方法

添加操作

boolean add(E element)           // 添加单个元素
boolean addAll(Collection c)     // 添加整个集合

删除操作

boolean remove(Object o)        // 删除单个元素
boolean removeAll(Collection c) // 删除集合中所有元素
void clear()                     // 清空集合

查询操作

int size()                       // 返回元素个数
boolean isEmpty()                // 判断是否为空
boolean contains(Object o)       // 判断是否包含元素
boolean containsAll(Collection c)// 判断是否包含所有元素

遍历操作

Iterator iterator()          // 返回迭代器
for (E element : collection)     // 增强for循环

如何选择合适的集合?

需要按索引访问? → List(ArrayList)
需要去除重复元素? → Set(HashSet)
需要按键排序? → TreeSet / TreeMap
需要键值对存储? → Map(HashMap)
需要FIFO队列? → Queue(LinkedList)
需要两端操作? → Deque(ArrayDeque)

选择决策树

需要存储键值对?
    ├─ 是 → Map
    │     ├─ 需要排序 → TreeMap
    │     └─ 不需要 → HashMap
    │
    └─ 否 → Collection
          ├─ 需要保证顺序?
          │   ├─ 是,需要按索引 → List → ArrayList
          │   └─ 是,需要FIFO → Queue → LinkedList/ArrayDeque
          │
          └─ 不需要保证顺序?
                └─ Set → HashSet(通用)/ LinkedHashSet(保序)

集合使用示例

List使用示例

List languages = new ArrayList<>();
languages.add("Java");
languages.add("Python");
languages.add("Java");  // 可以重复

System.out.println(languages.get(0));  // "Java"
System.out.println(languages.size());   // 3
System.out.println(languages.indexOf("Java"));  // 0

Set使用示例

Set uniqueLanguages = new HashSet<>();
uniqueLanguages.add("Java");
uniqueLanguages.add("Python");
uniqueLanguages.add("Java");  // 被忽略,不会添加

System.out.println(uniqueLanguages.size());  // 2
System.out.println(uniqueLanguages.contains("Java"));  // true

Map使用示例

Map scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 87);
scores.put("Alice", 98);  // 键相同,值覆盖

System.out.println(scores.get("Alice"));     // 98
System.out.println(scores.keySet());          // [Alice, Bob]
System.out.println(scores.values());          // [98, 87]

常见错误

错误1:HashMap使用自定义对象作为键

// 错误:自定义类作为HashMap的键,必须重写hashCode和equals
class Person {
    String name;
    int age;
    // 没有重写hashCode和equals!
}

Map map = new HashMap<>();
map.put(new Person("张三", 20), "信息");
System.out.println(map.get(new Person("张三", 20)));  // null!找不到

// 正确做法:重写hashCode和equals
class Person {
    String name;
    int age;

    @Override
    public int hashCode() { return Objects.hash(name, age); }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }
}

错误2:HashSet/HashMap的键使用可变对象

Set> set = new HashSet<>();
List list = new ArrayList<>();
list.add("A");
set.add(list);

list.add("B");  // 修改了list的内容!
System.out.println(set.contains(list));  // false!找不到

// 原因:修改后hashCode变了,导致找不到

小结

  • 集合框架提供统一的数据存储和操作架构
  • List:有序、可重复、按索引访问 → ArrayList, LinkedList
  • Set:无序、不可重复 → HashSet, TreeSet, LinkedHashSet
  • Queue:先进先出 → LinkedList, ArrayDeque, PriorityQueue
  • Map:键值对、键不重复 → HashMap, TreeMap, LinkedHashMap
  • 选择集合时考虑:是否需要重复、是否需要排序、访问方式
  • 自定义对象作为Map的键必须重写hashCode和equals
☕ Java 在线代码编辑器
📝 运行结果