Java 后端面试的 基础底盘——集合、Object 契约、String、抽象/接口、Java 8 函数式(Lambda/Stream/Optional)、泛型、反射、异常这些是几乎每场面试必问的内容。
本模块按 基础 → 集合 → 函数式 → 进阶 → 算法 五层组织,每篇按 senior 标准写:原理 + 取舍 + 面试追问 + 生产踩坑 + 答题模板。
共 19 篇,约 350KB。可以按"推荐学习路径"按序读,也可以按"高频题映射"直接跳。
| 文档 | 一句话定位 |
|---|---|
| JDK / JRE / JVM 与版本演进 | 三者关系、Oracle JDK vs OpenJDK、LTS 版本(8/11/17/21)选型、关键特性时间线 |
| 基本数据类型与自动装箱 | 8 种基本类型、Integer 缓存 -128~127、float/double 精度、BigDecimal、parseInt vs valueOf |
| Object 类 | 11 个方法、equals/hashCode 契约、深浅拷贝、wait/notify 必须在 synchronized 内 |
| String 原理 | 不可变性、字符串常量池、intern、JDK 9 紧凑字符串、StringBuilder vs StringBuffer |
| 抽象类和接口 | 区别、Java 8 default/static、Java 9 private、设计选型 |
| 集合框架总览 | Collection vs Map 体系、线程安全分类、fail-fast vs fail-safe |
| 文档 | 一句话定位 |
|---|---|
| List | ArrayList 扩容 1.5x、LinkedList 双向链表、Vector 已淘汰、CopyOnWriteArrayList |
| HashMap | 数组+链表+红黑树、扰动函数、JDK 7 头插死循环、TreeMap、LinkedHashMap |
| Set | HashSet 包装 HashMap、TreeSet 红黑树、LinkedHashSet 保序、CopyOnWriteArraySet |
| Queue | Queue/Deque 体系、ArrayDeque vs LinkedList、PriorityQueue 二叉堆 |
| Comparable vs Comparator | 自然序 vs 定制序、签名/返回值约定、Comparator 链式 API |
| 文档 | 一句话定位 |
|---|---|
| Lambda 与函数式接口 | invokedynamic + LambdaMetafactory、4 大函数式接口、方法引用、effectively final |
| Stream API | 中间 vs 终端操作、惰性求值、Collectors、parallelStream 何时用 |
| Optional | 设计动机、orElse vs orElseGet、map/flatMap、不要做字段/参数 |
| 文档 | 一句话定位 |
|---|---|
| 异常体系 | Throwable 层级、Checked vs Unchecked、try-with-resources、异常吞掉的坑 |
| 泛型 | 类型擦除、桥接方法、PECS、<? extends> vs <? super>、不能 new T[] |
| 反射与动态代理 | Class/Method/Field、JDK Proxy(接口)vs CGLIB(继承)、Spring AOP 选型 |
注意:原 Java 模块下的 限流算法 已迁至 Microservice 模块,一致性哈希 已迁至 Distributed 模块——这两个话题本质属于分布式 / 微服务范畴,不是 Java 语言特性。
被问到这些题,直接跳到对应文档:
| 高频题 | 跳转 |
|---|---|
Integer a = 100, b = 100; a == b 是什么? |
基本类型 |
为什么 0.1 + 0.2 != 0.3? |
基本类型 |
| BigDecimal 怎么正确用? | 基本类型 |
| 自动装箱的底层是什么? | 基本类型 |
| parseInt 和 valueOf 区别? | 基本类型 |
| JDK / JRE / JVM 区别? | jdk |
| Oracle JDK 和 OpenJDK 区别? | jdk |
| 你们用什么版本?为什么? | jdk |
== 和 equals 区别? |
Object 类 |
| 重写 equals 必须重写 hashCode 吗?为什么? | Object 类 |
| Object 有哪些方法? | Object 类 |
| wait / notify 为什么要在 synchronized 里? | Object 类 |
| 浅拷贝和深拷贝?怎么实现深拷贝? | Object 类 |
| String 为什么不可变?为什么这么设计? | String 原理 |
String s = "abc" 创建几个对象? |
String 原理 |
new String("abc") 创建几个对象? |
String 原理 |
| intern() 干什么? | String 原理 |
| String、StringBuilder、StringBuffer 区别? | String 原理 |
| 抽象类和接口区别?什么时候用哪个? | 抽象类和接口 |
| Java 8 接口 default 方法解决了什么问题? | 抽象类和接口 |
| 接口能多继承吗?菱形继承怎么处理? | 抽象类和接口 |
| 高频题 | 跳转 |
|---|---|
| 集合体系画一下? | 集合框架总览 |
| ArrayList 怎么扩容? | List |
| ArrayList 和 LinkedList 区别? | List |
| LinkedList 真比 ArrayList 头插快吗? | List |
| Vector 和 ArrayList 区别?为什么不推荐? | List |
| CopyOnWriteArrayList 原理?适用场景? | List |
| HashMap 数据结构?JDK 7 vs 8 区别? | HashMap |
| HashMap 的 hash 函数为什么要扰动? | HashMap |
| 链表什么时候转红黑树?为什么是 8? | HashMap |
| HashMap 怎么扩容?为什么是 2 的幂? | HashMap |
| JDK 7 HashMap 多线程死循环? | HashMap |
| HashMap、TreeMap、LinkedHashMap 区别? | HashMap |
| HashSet 怎么保证不重复?底层是什么? | Set |
| TreeSet 怎么排序? | Set |
| Queue 和 Deque 关系? | Queue |
| ArrayDeque 和 LinkedList 选哪个做栈? | Queue |
| PriorityQueue 是什么数据结构? | Queue |
| Comparable 和 Comparator 区别? | Comparator |
| compareTo 返回什么?写反了会有什么问题? | Comparator |
| 高频题 | 跳转 |
|---|---|
| Lambda 和匿名内部类区别? | Lambda |
| Lambda 为什么用 invokedynamic? | Lambda |
| 4 大函数式接口? | Lambda |
| 闭包变量为什么必须 effectively final? | Lambda |
| 方法引用 4 种形式? | Lambda |
| Stream 中间操作 vs 终端操作? | Stream |
| Stream 是惰性求值什么意思? | Stream |
| parallelStream 什么时候用? | Stream |
| Collectors.toMap 重复 key 怎么处理? | Stream |
| reduce 和 collect 区别? | Stream |
| Optional 的 orElse 和 orElseGet 区别? | Optional |
| Optional 能做字段/参数吗? | Optional |
| Optional.of vs ofNullable? | Optional |
| 高频题 | 跳转 |
|---|---|
| 异常体系画一下? | 异常体系 |
| Checked 和 Unchecked 区别?什么时候抛 RuntimeException? | 异常体系 |
| Error 能 catch 吗? | 异常体系 |
| try-finally 里 return,结果是什么? | 异常体系 |
| try-with-resources 原理? | 异常体系 |
| 泛型类型擦除是什么?带来什么影响? | 泛型 |
List<Integer> 和 List<String> 是同一个类吗? |
泛型 |
<? extends T> 和 <? super T>(PECS)? |
泛型 |
为什么 new T[] 编译不过? |
泛型 |
| 反射调用慢吗?为什么? | 反射与动态代理 |
| JDK Proxy 和 CGLIB 区别? | 反射与动态代理 |
| Spring AOP 默认用哪个? | 反射与动态代理 |
| Method.invoke 内部做了什么? | 反射与动态代理 |
限流算法、一致性哈希迁至 Distributed 模块。
基础层(必修)
1. JDK / JRE / JVM ← 全局视角
2. 基本数据类型与自动装箱 ← Integer 缓存 / BigDecimal 是高频陷阱
3. Object 类 ← equals/hashCode 契约决定后面 HashMap 的正确性
4. String 原理 ← 不可变 + 常量池
5. 抽象类和接口 ← 设计的两种基础抽象
集合层(高频考区)
6. 集合框架总览 ← 体系图
7. List ← 最常用
8. HashMap ← 最高频,必背
9. Set / Queue ← 边角但常考
10. Comparator ← 排序协议
函数式层(Java 8+ 必考)
11. Lambda 与函数式接口 ← invokedynamic + LambdaMetafactory
12. Stream API ← 集合处理范式革命
13. Optional ← NPE 解药,但 90% 用错
进阶层
14. 异常体系 ← 必背 Throwable
15. 泛型 ← 类型擦除是面试坑
16. 反射与动态代理 ← Spring AOP / MyBatis 都靠它
> 限流算法 / 一致性哈希 → 见 [Distributed 模块](../Distributed/README.md)。
每篇看 答题模板 一节就够:
基础
集合
函数式(Java 8+)
进阶
| 维度 | List | Set | Map | Queue |
|---|---|---|---|---|
| 重复 | ✅ | ❌ | key ❌ | ✅ |
| 有序 | ✅ 插入序 | 看实现 | 看实现 | FIFO/优先级 |
| 经典实现 | ArrayList | HashSet | HashMap | ArrayDeque |
| 排序实现 | — | TreeSet | TreeMap | PriorityQueue |
| 保插入序 | ArrayList | LinkedHashSet | LinkedHashMap | LinkedList |
| 线程安全 | CopyOnWriteArrayList | CopyOnWriteArraySet | ConcurrentHashMap | ConcurrentLinkedQueue |
| 常量 | 值 | 含义 |
|---|---|---|
| DEFAULT_INITIAL_CAPACITY | 16 | 默认初始容量 |
| MAXIMUM_CAPACITY | 2^30 | 最大容量 |
| DEFAULT_LOAD_FACTOR | 0.75 | 负载因子 |
| TREEIFY_THRESHOLD | 8 | 链表→红黑树阈值 |
| UNTREEIFY_THRESHOLD | 6 | 红黑树→链表阈值 |
| MIN_TREEIFY_CAPACITY | 64 | 树化的最小数组长度 |
1. 自反性:a.equals(a) == true
2. 对称性:a.equals(b) == b.equals(a)
3. 传递性:a.equals(b) && b.equals(c) → a.equals(c)
4. 一致性:多次调用结果一致(不变状态)
5. 与 hashCode 的契约:
- a.equals(b) == true → a.hashCode() == b.hashCode()
- 反之不成立(哈希冲突)
6. 与 null:a.equals(null) == false
| 版本 | 发布时间 | 默认 GC | 关键特性 |
|---|---|---|---|
| JDK 8 | 2014 | Parallel | Lambda、Stream、接口 default 方法、Optional |
| JDK 11 | 2018 | G1 | var、HttpClient、ZGC(实验)、移除 Java EE |
| JDK 17 | 2021 | G1 | sealed class、record、文本块、Pattern Matching |
| JDK 21 | 2023 | G1 | 虚拟线程(正式)、Pattern for switch、序列集合 |
Producer Extends, Consumer Super
生产者用 extends(只读出,类型是 T 或子类)
消费者用 super (只写入,类型是 T 或父类)
写入:List<? extends Number> ❌ 不能 add
读出:List<? super Integer> ✅ 但读出的是 Object
| 接口 | 方法 | 含义 | 数值版 |
|---|---|---|---|
Function<T,R> |
R apply(T) |
一进一出 | IntFunction / ToIntFunction |
Consumer<T> |
void accept(T) |
消费 | IntConsumer |
Supplier<T> |
T get() |
生产 | IntSupplier |
Predicate<T> |
boolean test(T) |
判断 | IntPredicate |
BiFunction<T,U,R> |
R apply(T, U) |
二进一出 | — |
UnaryOperator<T> |
T apply(T) |
一进一出(同型) | IntUnaryOperator |
方法引用 4 种:Integer::parseInt(静态)、obj::method(绑定实例)、String::length(未绑定,参数当 receiver)、ArrayList::new(构造器)。
中间操作(惰性):filter / map / flatMap / sorted / distinct / limit / skip / peek
终端操作(触发):collect / reduce / forEach / count / findFirst / anyMatch / sum
数值流避免装箱:mapToInt / mapToLong / mapToDouble → IntStream / LongStream / DoubleStream
Collectors:toList / toMap / groupingBy / partitioningBy / counting / summingInt / averagingInt / joining
✅ 推荐 ❌ 反模式
opt.map(...).orElse(...) if (opt.isPresent()) { opt.get()... }
opt.ifPresent(...) if (opt.isPresent()) { ... }
ofNullable(maybeNull) of(maybeNull) ← null 抛 NPE
orElseGet(() -> compute()) orElse(compute()) ← 无论如何都跑
仅做返回值 做字段 / 参数 / 集合元素
| 维度 | 反射 | JDK Proxy | CGLIB |
|---|---|---|---|
| 限制 | 无 | 必须基于接口 | 不能代理 final 类/方法 |
| 实现 | Method.invoke | InvocationHandler + Proxy | 字节码生成子类 |
| 性能 | 慢(无内联) | 比反射快(生成类) | 接近原生(FastClass) |
| Spring AOP | — | 有接口默认走 | 无接口 / 强制配置 |
| 坑 | 文档 |
|---|---|
| HashMap 多线程下数据丢失 / 死循环(JDK 7) | HashMap - 死循环 |
| 重写 equals 没重写 hashCode → HashMap 取不到 | Object 类 |
| Integer 缓存边界(-128~127) | 基本类型 |
| BigDecimal 用 double 构造 / equals 比 scale | 基本类型 |
Optional.orElse(compute()) 永远求值 |
Optional |
Collectors.toMap 重复 key 抛异常 |
Stream |
parallelStream 用错(IO 任务、共享 commonPool) |
Stream |
| String + 拼接在循环里性能爆炸 | String 原理 |
| ArrayList.subList() 不是普通 List | List |
| Arrays.asList 返回的不是 ArrayList | List |
| ConcurrentModificationException(fail-fast) | 集合总览 |
| Comparator 用减法溢出 | Comparator |
| 异常被 catch 后吞掉 | 异常体系 |
| 反射调用 setAccessible(true) 性能下降 | 反射与动态代理 |
按出现频率列出:
- HashMap 全家桶:数据结构 → 扰动 → 树化阈值 → 扩容 → 死循环 → 线程安全
- equals/hashCode:== vs equals → 重写规则 → HashMap 用法 → Integer 缓存
- String 三件套:不可变设计 → 常量池 → intern → StringBuilder
- 集合分类:体系图 → 线程安全实现 → fail-fast → CopyOnWrite
- 抽象/接口:何时用 → Java 8 default → 菱形继承
- 泛型:类型擦除 → PECS → 不能 new T[]
- 反射 + 代理:JDK Proxy vs CGLIB → Spring AOP → 性能
- 异常:Throwable → Checked vs Unchecked → try-finally-return → try-with-resources
每条主线对应至少一篇深度文档,按上方"高频题映射"快速跳转。
分布式相关高频题(限流、一致性哈希、CAP、事务、锁、ID、注册中心)→ 见 Distributed 模块。
- JVM 面试模块 — 内存模型、对象布局、GC,Java 运行时基础
- Concurrency 并发 — JMM、ConcurrentHashMap、线程池、AQS
- MySQL 面试模块 — B+Tree、索引、事务
- Redis 面试模块 — 缓存、分布式锁、布隆过滤器
- Spring — Bean 生命周期、AOP、自动装配
- Distributed 分布式 — 幂等、分布式事务