Java 集合框架:接口体系、常用实现、底层结构与选型(含线程安全)

Java 集合框架:接口体系、常用实现、底层结构与选型

0. 阅读指南

  • 日常开发最常用接口:ListMapSet (其次是 Queue/Deque)。

  • List<E>List接口E泛型元素类型ArrayListList实现类

  • "集合是否安全"通常指线程安全 :接口不承诺线程安全,取决于实现类 + 是否被多线程共享

  • 选型口诀:
    默认:ArrayList + HashMap + HashSet;要顺序:LinkedHash*;要排序/范围:Tree*;并发共享:ConcurrentHashMap;栈/队列:ArrayDeque


1. 什么是集合框架(Collection Framework)?

集合框架可以理解为:JDK 提供的一套"标准化的数据容器体系",用于存放和操作数据,让我们把精力放在业务逻辑上,而不是重复造轮子。

一个完整的集合框架通常包含三部分:

  1. 接口(Interfaces)

    定义抽象数据类型(如 List/Set/Map),让我们在代码里"面向接口编程",不关心具体实现。

  2. 实现(Implementations)

    接口的具体实现类(如 ArrayList/HashMap),内部使用不同数据结构以达到不同性能特点。

  3. 算法(Algorithms)

    对集合进行通用操作的方法(如排序、查找、批处理),常见于 CollectionsArrays 等工具类。


2. 集合体系结构:Collection vs Map

Java 容器主要分两大类:

2.1 Collection:单列集合(存一个个元素)

  • Collection<E>

    • List<E>:有序、可重复

    • Set<E>:唯一(去重)

    • Queue<E> / Deque<E>:队列/双端队列(工程中也很常用)

2.2 Map:键值对集合(key -> value)

  • Map<K,V> 不继承 Collection

    这是很多初学者容易混的点:Map 自成体系。


3.日常 Java 开发常用接口

1) List 体系:最常用

  • List<E> :最常用的集合接口之一,有序、可重复,绝大多数"结果集/展示列表/批量处理"都是 List。

  • (常一起用的通用能力)Collection<E> / Iterable<E> :很多方法参数会写成它们以提高通用性,但你写业务代码时还是以 List 为主。

2) Set 体系:常用,但场景更明确

  • Set<E> :核心就是去重(元素唯一),常用于"判重/过滤重复/黑白名单/去重统计"等。

  • SortedSet<E> / NavigableSet<E> :需要排序 + 范围查找 时会用(比如按时间/ID 有序、取区间、取最近值),但比 Set 少很多。

3) Map 体系:和 List 并列最常用

  • Map<K,V> :几乎所有项目都会大量用到,键值映射/快速查找/配置参数/聚合统计/分组结果等都离不开它。

  • ConcurrentMap<K,V>:并发场景(缓存、计数器、共享状态)常用,尤其在多线程/高并发服务里。

  • SortedMap<K,V> / NavigableMap<K,V> :需要按 key 有序 + 范围操作 时用(如时间线、区间查询),频率低于 Map


List<E> 是什么?和 ArrayList 有什么关系?
1 先一句话说清楚
  • List 是"规则/标准"(接口)

  • ArrayList 是"按这个规则做出来的具体东西"(实现类)

  • E 是"里面装什么类型的元素"(泛型)

2 用生活类比理解(最直观)

List 当成"插座标准 ",它规定了你必须支持哪些功能:

比如能 add()、能 get()、能 remove()......

ArrayList 就像"某个品牌按这个标准生产出来的插座 "。

同样符合 List 标准的,还有别的品牌/型号,比如 LinkedList

所以:

  • List:规定能力(接口)

  • ArrayList:具体实现(实现类)

3 E 到底是什么?

E 是泛型参数,意思是 Element(元素)

举例:

  • List<String>:只能装字符串

  • List<Integer>:只能装整数(实际上装的是 Integer,基本类型会装箱)

  • List<User>:只能装 User 对象

4 它们之间的关系(最关键的一句)

ArrayList 实现了 List

java 复制代码
ArrayList<E> implements List<E>

这句的意思就是:
ArrayList 具备 List 规定的一切功能。

5 为什么代码里常写 List = new ArrayList()

你经常看到这种写法:

java 复制代码
List<String> list = new ArrayList<>();

这叫面向接口编程 ,好处是:

以后如果你发现 ArrayList 不合适,想换成别的实现,改动很小:

java 复制代码
List<String> list = new LinkedList<>();

业务代码只认 List 的规则(add/get/remove),不关心底层用的是哪种实现。

6 一句话总结

List<E> 是一个"列表接口",规定了列表必须有哪些操作;ArrayListList 的一个实现类;E 表示列表里元素的类型。


4. List / Set / Map 的区别

4.1 List

  • 有序(有索引)

  • 可重复

  • 多数实现允许 null

  • 常见场景:结果集、分页列表、批量处理、展示数据

4.2 Set

  • 元素唯一(去重)

  • "无序"更准确说法:迭代顺序不保证(由具体实现决定)

  • HashSet/LinkedHashSet 通常允许一个 null

  • 常见场景:判重、去重、黑白名单、集合运算(交并差)

4.3 Map

  • key -> value 映射

  • key 必须唯一,value 可重复

  • HashMap 允许 1 个 null key;ConcurrentHashMap/Hashtable 不允许 null

  • 常见场景:按 id 查对象、分组统计、缓存、参数映射


5. 常用集合类有哪些?(开发最常见)

5.1 List 常用

  • ArrayList(最常用)

  • LinkedList(更多时候当 Deque 用)

  • Vector/Stack(老类,通常不推荐新项目使用)

5.2 Set 常用

  • HashSet

  • LinkedHashSet(保持插入顺序)

  • TreeSet(有序、支持范围查询)

5.3 Map 常用

  • HashMap(最常用)

  • LinkedHashMap(保持顺序 / 可实现 LRU)

  • TreeMap(按 key 排序 / 范围查询)

  • ConcurrentHashMap(并发场景)


6. 选型表:常用类 + 底层结构 + 复杂度

这张表就是"你该用哪个集合"的速查表。

典型场景 推荐实现类 接口 底层数据结构 典型复杂度 线程安全 备注
普通列表/结果集,随机访问多 ArrayList List 动态数组 Object[] get O(1),尾插均摊 O(1),中间改 O(n) 最常用 List
头尾频繁增删(队列/栈) ArrayDeque Deque 循环数组 头尾操作均摊 O(1) 推荐替代 Stack ;不允许 null
按优先级取最小/最大 PriorityQueue Queue offer/poll O(log n),peek O(1) 不保证遍历有序
判重/去重 HashSet Set 基于 HashMap 平均 O(1) 依赖 hashCode/equals
去重 + 保持插入顺序 LinkedHashSet Set LinkedHashMap(Hash + 双向链表) 平均 O(1) 遍历顺序=插入顺序
排序/范围查询(<=、区间) TreeSet NavigableSet 红黑树(TreeMap O(log n) 通常不接受 null(取决于比较器)
key 查 value / 分组统计 / 缓存 HashMap Map 数组 + 链表/红黑树(JDK8+) 平均 O(1) 允许 1 个 null key
Map 保持插入顺序 / LRU LinkedHashMap Map HashMap + 双向链表 平均 O(1) 可实现 LRU
key 有序 + 范围查询 TreeMap NavigableMap 红黑树 O(log n) 适合区间/最值
多线程共享 Map ConcurrentHashMap ConcurrentMap 并发哈希结构 并发下接近 O(1) 不允许 null;用原子 API
读多写少并发 List/Set CopyOnWriteArrayList/Set List/Set 写时复制数组 读 O(1),写 O(n) 配置/白名单很适合
简单粗暴同步包装 Collections.synchronizedXxx 多种 外层锁包装 取决于内部实现 遍历仍需手动同步

7. 集合"线程安全"到底怎么理解?(Map vs ConcurrentMap)

先给结论:接口不保证线程安全,看实现类 + 使用方式。

7.1 常见非线程安全(默认)

  • ArrayListHashMapHashSetLinkedHashMapTreeMap ...

如果它们只是方法内局部变量(每次请求新建、不共享),一般没问题。

7.2 常见线程安全 / 并发友好

  • ConcurrentHashMap(最常用并发 Map)

  • CopyOnWriteArrayList/Set(读多写少)

  • Collections.synchronizedMap/List/Set(...)(同步包装)

  • Vector/Hashtable/Stack(老的同步类,新项目一般不推荐)

7.3 并发容器也要"用对姿势"

错误写法(复合操作有竞态):

java 复制代码
if (!map.containsKey(k)) {
    map.put(k, v);
}

正确写法(原子操作):

java 复制代码
map.putIfAbsent(k, v);
// 或
map.computeIfAbsent(k, kk -> createValue());

8. 数组 vs 集合

  • 数组:长度固定;集合:通常可动态扩容

  • 数组可存基本类型(int[])和引用类型(String[]

    集合只能存引用类型,但基本类型会自动装箱List<Integer>

  • "数组必须同类型、集合可不同类型"这句容易误导:

    如果集合使用泛型(推荐),同样会限制类型;不使用泛型才可能混放,但不推荐。


9. 面试/实战速答模板

  • List/Set/Map 区别:List 有序可重复;Set 去重唯一;Map 键值映射 key 唯一。

  • ArrayList vs LinkedList:ArrayList 随机访问快;LinkedList 头尾增删更方便(常当 Deque)。

  • HashMap vs TreeMap:HashMap 无序但快;TreeMap 有序支持范围查询(O(log n))。

  • HashMap vs ConcurrentHashMap:前者非线程安全;后者并发友好且提供原子复合操作(但不允许 null)。


10. 总结

  • 最常用接口:ListMapSet

  • 最常用实现:ArrayListHashMapHashSet

  • 要顺序:LinkedHashMap/LinkedHashSet;要排序/范围:TreeMap/TreeSet

  • 多线程共享:优先 ConcurrentHashMap,并用 computeIfAbsent/putIfAbsent 这类原子方法

相关推荐
键盘鼓手苏苏2 小时前
Flutter for OpenHarmony 实战:Envied — 环境变量与私钥安全守护者
开发语言·安全·flutter·华为·rust·harmonyos
坚持就完事了2 小时前
Java泛型
java·开发语言
志栋智能2 小时前
AI驱动的安全自动化机器人:从“告警疲劳”到“智能免疫”的防御革命
运维·人工智能·安全·机器人·自动化
浮生09192 小时前
DHUOJ 基础 85 86 87
数据结构·c++·算法
cyforkk2 小时前
YAML 基础语法与编写规范详解
java
亓才孓2 小时前
[Spring测试]TestRestTemplate
java·后端·spring
逆光的July2 小时前
扫码登录的设计与实现
java
Miqiuha2 小时前
工作答辩框架
java·开发语言
happymaker06262 小时前
Java学习日记——DAY25(JavaSE完结)
java·开发语言·学习