杰瑞科技汇

java中的collection

  1. 核心概念Collection 是什么?它和 Collections 有什么区别?
  2. 整体架构图Collection 在整个集合框架中的位置。
  3. 主要接口详解List, Set, Queue 的特点和常用实现类。
  4. 遍历方式:如何高效地遍历集合。
  5. 常用工具类Collections 类提供了哪些静态方法。
  6. 总结与选择:如何根据业务场景选择合适的集合。

核心概念:Collection vs Collections

这是一个非常常见的面试题,也是初学者容易混淆的地方。

java中的collection-图1
(图片来源网络,侵删)

java.util.Collection

  • 它是一个接口,位于集合框架的顶层。
  • 它是 List, Set, Queue 这三个核心接口的父接口
  • 它定义了所有单列集合(存储一组对象)最共有的方法,
    • add(E e): 添加元素
    • remove(Object o): 删除元素
    • contains(Object o): 判断是否包含元素
    • size(): 获取元素个数
    • iterator(): 获取迭代器,用于遍历集合
    • isEmpty(): 判断集合是否为空
  • 注意Collection 接口本身不直接提供实现,我们通常使用的是它的子接口(如 List)的实现类(如 ArrayList)。

java.util.Collections

  • 它是一个工具类,里面包含的都是静态方法
  • 它提供了一系列对 CollectionMap 进行操作的算法工具方法
    • 排序:sort(List<T> list)
    • 查找:binarySearch(List<? extends Comparable<? super T>> list, T key)
    • 线程安全化:synchronizedList(List<T> list)
    • 创建不可变集合:unmodifiableList(List<? extends T> list)
    • 填充:fill(List<? super T> list, T obj)

一句话总结

  • Collection 是一个接口,是集合的“祖宗”。
  • Collections 是一个工具类,是集合的“工具箱”。

整体架构图

理解了 Collection 的位置,再看下面的架构图就清晰多了。

  • 最顶层Iterable 接口,这是整个集合框架的“根”,实现了这个接口的类就可以使用 for-each 循环。Collection 继承了 Iterable
  • 核心接口
    • Collection: 所有单列集合的父接口。
    • Map: 存储键值对 的集合,不属于 Collection 体系,但同样是集合框架的核心部分。
  • 三大子接口
    • List: 有序、可重复。
    • Set: 无序(指存取顺序)、不可重复。
    • Queue: 队列,遵循先进先出 的原则。
  • 实现类:就是我们在日常编码中真正使用的类,如 ArrayList, HashSet, HashMap 等。

主要接口详解

List 接口

特点:有序(存储顺序和取出顺序一致)、可重复(允许存储 null 值)。

实现类 底层结构 特点 适用场景
ArrayList 动态数组 查询快(随机访问 O(1))
增删慢(需要移动元素 O(n))
非线程安全
最常用,适用于元素数量不固定、需要频繁随机访问的场景,如读取列表数据。
LinkedList 双向链表 查询慢(需要遍历 O(n))
增删快(只需修改指针 O(1))
非线程安全
适用于需要频繁在头部或中间插入/删除元素的场景,如实现队列、栈。
Vector 动态数组 功能与 ArrayList 相同
线程安全(但性能差,已不推荐使用)
老代码中可能见到,新项目应使用 Collections.synchronizedList(new ArrayList<>())CopyOnWriteArrayList

示例代码:

java中的collection-图2
(图片来源网络,侵删)
import java.util.ArrayList;
import java.util.List;
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
names.add("Alice"); // 允许重复
names.add(0, "Charlie"); // 在指定位置插入
System.out.println(names.get(1)); // 输出: Alice
System.out.println(names.contains("Bob")); // 输出: true

Set 接口

特点:无序(指存取顺序不保证一致)、不可重复(不能存储重复元素)。Set 的具体实现类决定了其元素的“无序”程度。

实现类 底层结构 特点 适用场景
HashSet 哈希表 (HashMap) 存取顺序不一致(无序)
查找、添加、删除速度快(平均 O(1))
非线程安全
最常用,适用于要求不重复、不关心顺序的场景,如去重、作为键的集合。
LinkedHashSet 哈希表 + 链表 有序(按插入顺序)
继承 HashSet,性能略低于 HashSet
非线程安全
既要保证元素不重复,又需要保持插入顺序的场景,如记录最近访问的用户。
TreeSet 红黑树 (TreeMap) 排序(默认自然排序,或指定 Comparator)
查找、添加、删除速度较快(O(log n))
非线程安全
需要对元素进行排序的场景,如按分数排名。

注意HashSetLinkedHashSet 要求元素必须重写 equals()hashCode() 方法;TreeSet 要求元素必须实现 Comparable 接口或提供 Comparator

示例代码:

import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
// HashSet
Set<String> uniqueNames = new HashSet<>();
uniqueNames.add("David");
uniqueNames.add("Eve");
uniqueNames.add("David"); // 重复元素,不会被添加
System.out.println(uniqueNames); // 输出可能是 [Eve, David],顺序不确定
// TreeSet
Set<Integer> numbers = new TreeSet<>();
numbers.add(10);
numbers.add(5);
numbers.add(20);
System.out.println(numbers); // 输出 [5, 10, 20],自动排序

Queue 接口

特点:队列,遵循先进先出 的原则,常用于多线程场景。

实现类 特点 适用场景
LinkedList 实现了 Queue 接口,可作为队列使用。 简单的 FIFO 队列。
PriorityQueue 优先队列,不遵循 FIFO,而是按元素的“优先级”出队(默认自然排序)。 任务调度,如执行紧急任务。
ArrayBlockingQueue 有界阻塞队列,基于数组,必须指定容量,当队列满/空时,put/take 操作会阻塞。 生产者-消费者模型,线程池。
LinkedBlockingQueue 无界/有界阻塞队列,基于链表。 同上,容量可选,吞吐量通常高于 ArrayBlockingQueue

示例代码:

import java.util.LinkedList;
import java.util.Queue;
Queue<String> queue = new LinkedList<>();
queue.add("A");
queue.add("B");
queue.add("C");
// FIFO
System.out.println(queue.poll()); // 移除并返回头部元素,输出: A
System.out.println(queue.peek()); // 查看头部元素但不移除,输出: B

遍历方式

有四种主要的遍历方式,推荐使用 迭代器for-each 循环

迭代器遍历(最安全、最通用)

可以在遍历时安全地删除元素。

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String item = iterator.next();
    if ("B".equals(item)) {
        iterator.remove(); // 安全删除
    }
}

for-each 循环(最简洁、推荐)

底层也是使用的迭代器,不能在遍历时修改集合(会抛出 ConcurrentModificationException)。

for (String item : list) {
    System.out.println(item);
}

传统 for 循环(适用于 List

可以通过索引访问,但不适用于 SetQueue

for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

JDK 8+ Stream API(函数式风格,功能强大)

非常适合进行复杂的链式操作,如过滤、映射、聚合。

list.stream()
    .filter(s -> !"B".equals(s)) // 过滤掉 B
    .forEach(System.out::println); // 打印

常用工具类 Collections

Collections 类提供了大量静态方法来操作集合。

List<Integer> numbers = new ArrayList<>(Arrays.asList(3, 1, 4, 1, 5));
// 1. 排序
Collections.sort(numbers); // [1, 1, 3, 4, 5]
// 2. 二分查找(前提是集合已排序)
int index = Collections.binarySearch(numbers, 4); // 返回 3
// 3. 反转
Collections.reverse(numbers); // [5, 4, 3, 1, 1]
// 4. 打乱顺序
Collections.shuffle(numbers);
// 5. 线程安全化
List<Integer> synchronizedList = Collections.synchronizedList(new ArrayList<>());
// 6. 创建不可变集合
List<Integer> unmodifiableList = Collections.unmodifiableList(numbers);
// unmodifiableList.add(10); // 会抛出 UnsupportedOperationException

总结与选择:如何选择合适的集合?

这是一个非常重要的问题,选择合适的集合能让程序更高效、更健壮。

场景 首选 次选/原因
需要存储一组对象,允许重复,关心顺序 ArrayList LinkedList (如果频繁在头部/中间增删)
需要存储一组对象,不允许重复,不关心顺序 HashSet LinkedHashSet (如果需要保持插入顺序)
需要存储一组对象,不允许重复,需要排序 TreeSet HashSet + 手动排序 (如果排序不频繁)
需要实现 FIFO 队列 LinkedListArrayBlockingQueue (多线程) LinkedList 简单,ArrayBlockingQueue 功能更强
需要实现优先队列 PriorityQueue -
需要键值对存储 HashMap TreeMap (需要排序), LinkedHashMap (需要插入顺序)
需要线程安全的集合 ConcurrentHashMap, CopyOnWriteArrayList Collections.synchronizedXxx() (性能较差)

希望这份详细的梳理能帮助你彻底理解 Java 中的 Collection

分享:
扫描分享到社交APP
上一篇
下一篇