Java 校招面试题复盘清单
这是一份 Java 校招面试题复盘清单。
它不适合当作“背诵稿”逐字记忆,更适合当作复习地图:先知道面试会问哪些方向,再把每个问题整理成可以讲清楚的核心答案。
Java 校招面试通常会围绕三部分展开:
| 模块 | 占比 | 重点 |
|---|---|---|
| 技术基础 | 约 40% | Java、Spring、MySQL、Redis、JVM、并发 |
| 项目深挖 | 约 40% | 项目背景、技术选型、难点、优化、问题排查 |
| 学习能力 | 约 20% | 最近在学什么、为什么做 Java、如何解决问题 |
如果项目里有 Elasticsearch,那么 ES 往往会成为面试官重点追问的方向。
Java 基础
Section titled “Java 基础”HashMap 的底层原理是什么
Section titled “HashMap 的底层原理是什么”HashMap 底层主要是数组、链表和红黑树。
当放入一个 key-value 时,会先根据 key 的 hashCode() 计算 hash,再定位到数组下标。如果该位置没有元素,就直接放入;如果已经有元素,就会形成链表或红黑树。
在 Java 8 之后,当链表长度达到一定阈值,并且数组容量足够大时,链表会转换为红黑树,用来提高查询效率。
可以这样回答:
HashMap 通过 hash 定位数组下标,数组中每个位置叫 bucket。发生 hash 冲突时,Java 8 以前主要用链表,Java 8 之后链表过长会转为红黑树。扩容时会重新计算元素位置,所以 HashMap 的性能和初始容量、负载因子、hash 分布都有关系。
HashMap 为什么线程不安全
Section titled “HashMap 为什么线程不安全”HashMap 没有做同步控制,多线程同时读写时可能出现数据覆盖、状态不一致、扩容异常等问题。
常见风险:
- 多个线程同时
put,可能覆盖彼此写入。 - 扩容时结构变化,其他线程同时访问可能拿到异常结果。
- 统计数量
size可能不准确。
所以多线程场景通常使用 ConcurrentHashMap。
ConcurrentHashMap 如何实现线程安全
Section titled “ConcurrentHashMap 如何实现线程安全”Java 8 中,ConcurrentHashMap 主要通过 CAS 和 synchronized 保证线程安全。
它不是给整张表加一把大锁,而是尽量缩小锁粒度。
常见回答:
Java 8 的 ConcurrentHashMap 底层也是数组、链表和红黑树。插入时,如果桶为空,会通过 CAS 放入节点;如果桶不为空,会对桶头节点加 synchronized,只锁当前桶。这样既保证线程安全,又比 Hashtable 整表加锁性能更好。
ArrayList 和 LinkedList 的区别
Section titled “ArrayList 和 LinkedList 的区别”ArrayList 底层是动态数组,LinkedList 底层是双向链表。
| 对比项 | ArrayList | LinkedList |
|---|---|---|
| 底层结构 | 动态数组 | 双向链表 |
| 随机访问 | 快,按下标访问 O(1) | 慢,需要遍历 |
| 中间插入删除 | 需要移动元素 | 找到节点后修改指针 |
| 内存占用 | 相对较少 | 每个节点要存前后指针 |
| 常用场景 | 查询多 | 插入删除多,但实际也要看位置 |
面试里要注意:不要简单说 LinkedList 插入删除一定快。因为如果要先按索引找到位置,遍历本身也有成本。
String、StringBuilder、StringBuffer 的区别
Section titled “String、StringBuilder、StringBuffer 的区别”String 是不可变对象,每次修改都会产生新字符串。
StringBuilder 是可变字符序列,线程不安全,但性能较好。
StringBuffer 也是可变字符序列,方法加了同步,线程安全,但性能通常低于 StringBuilder。
常见选择:
- 少量字符串拼接:直接用
String。 - 单线程大量拼接:用
StringBuilder。 - 多线程共享拼接对象:用
StringBuffer,但实际业务中较少这样用。
equals 和 == 的区别
Section titled “equals 和 == 的区别”== 比较的是两边是否相等。
对于基本类型,比较的是值。
对于引用类型,比较的是对象地址。
equals() 是对象方法,默认实现也是比较地址,但很多类会重写它,比如 String 会比较字符串内容。
String a = new String("hello");String b = new String("hello");
System.out.println(a == b); // falseSystem.out.println(a.equals(b)); // trueJava 中的异常体系是什么
Section titled “Java 中的异常体系是什么”Java 异常体系的顶层是 Throwable。
它下面主要分为:
Error:严重错误,程序通常不主动处理,比如OutOfMemoryError。Exception:程序可以捕获和处理的异常。
Exception 又分为:
- checked exception:编译期异常,必须处理或声明抛出。
- unchecked exception:运行时异常,继承自
RuntimeException,例如空指针、数组越界。
面试里可以补一句:业务开发中不要滥用异常控制正常流程,异常更适合表示非预期情况。
反射是 Java 在运行时获取类信息、创建对象、调用方法、访问字段的能力。
常见应用场景:
- Spring 创建 Bean、依赖注入。
- MyBatis 映射对象字段。
- 注解解析。
- 测试框架调用测试方法。
- 动态代理。
反射灵活,但也有缺点:性能相对普通调用更低,可读性和安全性更差。
Java 并发
Section titled “Java 并发”什么是线程,什么是进程
Section titled “什么是线程,什么是进程”进程是操作系统资源分配的基本单位。一个应用程序运行起来通常就是一个进程。
线程是 CPU 调度的基本单位,一个进程中可以包含多个线程。
可以这样回答:
进程拥有独立的内存空间,线程共享同一进程的内存资源。线程切换成本通常低于进程,但共享数据也会带来线程安全问题。
synchronized 的原理是什么
Section titled “synchronized 的原理是什么”synchronized 可以修饰方法或代码块,用来保证同一时间只有一个线程进入临界区。
它依赖对象监视器锁,也就是 monitor。
进入同步代码块时,线程尝试获取对象锁;执行完或异常退出时释放锁。
可以补充:
- 修饰普通方法,锁的是当前对象
this。 - 修饰静态方法,锁的是当前类的
Class对象。 - 修饰代码块,可以指定锁对象。
volatile 的作用是什么
Section titled “volatile 的作用是什么”volatile 主要有两个作用:
- 保证变量对多线程的可见性。
- 禁止指令重排序。
它不能保证复合操作的原子性。
比如 count++ 包含读取、加一、写回,不是一个原子操作,所以只加 volatile 仍然不安全。
常见场景:
- 状态标志位。
- 单例模式双重检查锁中的实例变量。
什么是线程池
Section titled “什么是线程池”线程池是提前创建并管理一组线程,任务来了以后交给线程池执行。
使用线程池的原因:
- 避免频繁创建和销毁线程。
- 控制并发线程数量。
- 提高响应速度。
- 统一管理任务队列、拒绝策略和线程生命周期。
ThreadPoolExecutor 核心参数有哪些
Section titled “ThreadPoolExecutor 核心参数有哪些”ThreadPoolExecutor 常见核心参数:
| 参数 | 作用 |
|---|---|
corePoolSize | 核心线程数 |
maximumPoolSize | 最大线程数 |
keepAliveTime | 非核心线程空闲存活时间 |
unit | 时间单位 |
workQueue | 任务队列 |
threadFactory | 线程创建工厂 |
handler | 拒绝策略 |
执行流程可以概括为:
核心线程未满 -> 创建核心线程核心线程已满 -> 放入任务队列队列满了 -> 创建非核心线程线程数达到最大且队列也满 -> 执行拒绝策略什么是死锁,如何避免
Section titled “什么是死锁,如何避免”死锁是多个线程互相持有对方需要的资源,导致都无法继续执行。
死锁常见四个条件:
- 互斥。
- 请求并保持。
- 不可剥夺。
- 循环等待。
避免方式:
- 固定加锁顺序。
- 减少锁范围。
- 使用超时锁。
- 避免嵌套锁。
- 使用并发工具类代替手写锁。
JVM 的内存结构是什么
Section titled “JVM 的内存结构是什么”JVM 运行时数据区主要包括:
- 程序计数器。
- Java 虚拟机栈。
- 本地方法栈。
- 堆。
- 方法区。
线程私有:
- 程序计数器。
- Java 虚拟机栈。
- 本地方法栈。
线程共享:
- 堆。
- 方法区。
堆和栈的区别
Section titled “堆和栈的区别”栈主要存放方法调用相关信息,比如局部变量表、操作数栈、方法出口等。
堆主要存放对象实例,是垃圾回收重点关注的区域。
| 对比项 | 栈 | 堆 |
|---|---|---|
| 线程关系 | 线程私有 | 线程共享 |
| 存储内容 | 方法调用、局部变量 | 对象实例 |
| 生命周期 | 随方法调用入栈出栈 | 由 GC 管理 |
| 常见错误 | StackOverflowError | OutOfMemoryError |
什么是垃圾回收
Section titled “什么是垃圾回收”垃圾回收是 JVM 自动回收不再使用对象的机制。
判断对象是否可回收,主流方法是可达性分析:从 GC Roots 出发,能到达的对象是存活对象,不能到达的对象可以被回收。
常见 GC Roots:
- 虚拟机栈中的引用。
- 方法区中的静态变量引用。
- 常量引用。
- 本地方法栈中的引用。
常见 GC 算法有哪些
Section titled “常见 GC 算法有哪些”常见算法:
- 标记-清除:先标记垃圾,再清除,可能产生内存碎片。
- 复制算法:把存活对象复制到另一块区域,适合新生代。
- 标记-整理:标记后整理存活对象,减少碎片。
- 分代收集:按对象生命周期分区,不同区域用不同算法。
什么情况下会发生 OOM
Section titled “什么情况下会发生 OOM”OOM 是内存不足导致的错误。
常见原因:
- 创建了大量对象,堆空间不足。
- 大对象过多。
- 内存泄漏,旧对象一直被引用。
- 线程过多导致栈空间不足。
- 元空间加载类过多。
排查时通常会看日志、堆 dump、GC 情况和对象引用链。
JVM 调优一般关注哪些参数
Section titled “JVM 调优一般关注哪些参数”常见关注点:
- 堆大小:
-Xms、-Xmx - 新生代大小:
-Xmn - 元空间大小:
-XX:MetaspaceSize - GC 收集器选择。
- GC 日志。
- 停顿时间和吞吐量。
调优不是盲目改参数,而是先看现象:内存是否够、GC 是否频繁、停顿是否过长、对象是否异常增长。
Spring
Section titled “Spring”什么是 IoC
Section titled “什么是 IoC”IoC 是控制反转。
原本对象由程序自己创建和管理,现在交给 Spring 容器创建和管理。
DI 依赖注入是 IoC 的一种实现方式。比如一个 Service 依赖 Mapper,不需要自己 new,而是由 Spring 注入。
什么是 AOP
Section titled “什么是 AOP”AOP 是面向切面编程,用来把通用逻辑从业务代码中抽离出来。
常见场景:
- 日志。
- 权限校验。
- 事务。
- 监控统计。
- 接口耗时。
核心思想是:不修改业务方法本身,在方法执行前后织入增强逻辑。
Bean 的生命周期是什么
Section titled “Bean 的生命周期是什么”简化流程:
实例化 -> 属性注入 -> 初始化前后处理 -> 初始化方法 -> 使用 -> 销毁常见扩展点:
- 构造方法。
- 属性填充。
BeanPostProcessor。InitializingBean或init-method。DisposableBean或destroy-method。
为什么使用 Spring Boot
Section titled “为什么使用 Spring Boot”Spring Boot 主要解决传统 Spring 项目配置繁琐的问题。
优势:
- 自动配置。
- 内置 Web 容器。
- starter 依赖简化。
- 快速创建项目。
- 方便监控和部署。
一句话回答:
Spring Boot 让 Spring 项目更容易启动和维护,它通过自动配置和 starter 机制减少大量 XML 或手动配置。
Spring Boot 自动配置原理是什么
Section titled “Spring Boot 自动配置原理是什么”自动配置的核心是根据类路径、配置文件和条件注解,自动创建合适的 Bean。
常见关键词:
- starter。
- auto configuration。
@EnableAutoConfiguration。- 条件注解,比如
@ConditionalOnClass、@ConditionalOnMissingBean。
面试中可以这样说:
Spring Boot 会根据引入的依赖和当前环境判断是否满足条件,如果满足,就把对应配置类里的 Bean 注册到容器中。
什么是 RESTful API
Section titled “什么是 RESTful API”RESTful API 是一种接口设计风格。
核心思想:
- 使用 URL 表示资源。
- 使用 HTTP 方法表示操作。
- 使用状态码表示结果。
示例:
GET /users/1 查询用户POST /users 创建用户PUT /users/1 更新用户DELETE /users/1 删除用户MySQL 索引是什么
Section titled “MySQL 索引是什么”索引是帮助 MySQL 快速查找数据的数据结构。
可以理解为书的目录。没有索引时,数据库可能要全表扫描;有索引时,可以更快定位数据。
索引能提高查询效率,但会增加写入成本和存储空间。
MySQL 为什么使用 B+Tree
Section titled “MySQL 为什么使用 B+Tree”B+Tree 适合磁盘存储和范围查询。
原因:
- 树高度低,减少磁盘 IO。
- 非叶子节点只存索引,能放更多 key。
- 叶子节点之间有链表,范围查询效率高。
- 查询性能稳定。
什么是覆盖索引
Section titled “什么是覆盖索引”覆盖索引指查询需要的字段都能从索引中获得,不需要回表查询。
比如有联合索引 (name, age):
SELECT name, age FROM user WHERE name = 'xiaoxi';如果查询字段都在索引里,就可能走覆盖索引。
什么情况下索引会失效
Section titled “什么情况下索引会失效”常见情况:
- 对索引列使用函数。
- 对索引列做计算。
- 使用左模糊匹配,例如
LIKE '%abc'。 - 联合索引不符合最左前缀原则。
- 隐式类型转换。
OR条件使用不当。
事务是一组数据库操作的集合,要么全部成功,要么全部失败。
比如下单时:
- 创建订单。
- 扣减库存。
- 扣减余额。
这些操作应该作为一个整体处理。
MySQL 事务的 ACID
Section titled “MySQL 事务的 ACID”| 特性 | 含义 |
|---|---|
| Atomicity 原子性 | 事务要么全部成功,要么全部失败 |
| Consistency 一致性 | 事务前后数据满足约束 |
| Isolation 隔离性 | 并发事务之间互相隔离 |
| Durability 持久性 | 事务提交后数据持久保存 |
什么是 MVCC
Section titled “什么是 MVCC”MVCC 是多版本并发控制。
它通过保存数据的多个版本,让读写尽量不互相阻塞。
在 InnoDB 中,MVCC 主要依赖:
- 隐藏字段。
- undo log。
- ReadView。
常见作用是支持可重复读和快照读。
Redis 为什么这么快
Section titled “Redis 为什么这么快”常见原因:
- 数据主要在内存中。
- 使用高效数据结构。
- 单线程命令执行避免大量锁竞争。
- IO 多路复用。
- C 语言实现,执行效率高。
Redis 有哪些数据结构
Section titled “Redis 有哪些数据结构”常见类型:
- String。
- Hash。
- List。
- Set。
- Sorted Set。
- Bitmap。
- HyperLogLog。
- Geo。
- Stream。
什么是缓存穿透
Section titled “什么是缓存穿透”缓存穿透是请求的数据在缓存和数据库中都不存在,导致请求持续打到数据库。
解决方式:
- 缓存空对象。
- 布隆过滤器。
什么是缓存击穿
Section titled “什么是缓存击穿”缓存击穿是热点 Key 过期瞬间,大量并发请求同时打到数据库。
解决方式:
- 互斥锁。
- 逻辑过期。
什么是缓存雪崩
Section titled “什么是缓存雪崩”缓存雪崩是大量 Key 同时过期,或者 Redis 整体不可用,导致大量请求涌向数据库。
解决方式:
- 过期时间加随机值。
- 多级缓存。
- 限流降级。
- Redis 高可用。
Elasticsearch
Section titled “Elasticsearch”什么是 Elasticsearch
Section titled “什么是 Elasticsearch”Elasticsearch 是一个分布式搜索和分析引擎,常用于全文搜索、日志检索、商品搜索等场景。
它底层基于 Lucene,对外提供 REST API,支持分布式、倒排索引和复杂查询。
什么是倒排索引
Section titled “什么是倒排索引”倒排索引是从词到文档的映射。
普通索引更像:
文档 -> 包含哪些词倒排索引更像:
词 -> 出现在哪些文档中这就是 ES 做全文搜索快的重要原因。
ES 中 index、type、document 是什么
Section titled “ES 中 index、type、document 是什么”index 类似一类数据的集合。
document 是一条 JSON 数据。
type 在早期版本中用于区分类型,但新版本已经逐步移除,不建议在新项目中依赖 type。
可以类比:
| ES | 关系型数据库 |
|---|---|
| index | table 或 database 的某种集合概念 |
| document | row |
| field | column |
什么是 DSL 查询
Section titled “什么是 DSL 查询”DSL 是 Elasticsearch 的查询语言,使用 JSON 描述查询条件。
示例:
{ "query": { "match": { "title": "redis" } }}bool query 有哪些条件
Section titled “bool query 有哪些条件”常见条件:
must:必须匹配,影响评分。should:可选匹配,可能影响评分。filter:必须匹配,但不参与评分,适合过滤条件。must_not:必须不匹配。
为什么 Elasticsearch 搜索比 MySQL 快
Section titled “为什么 Elasticsearch 搜索比 MySQL 快”ES 在全文搜索场景下更快,主要因为它使用倒排索引。
MySQL 更擅长结构化数据查询和事务处理,全文检索不是它最核心的场景。
可以这样回答:
ES 会先对文本分词,再建立词到文档的倒排索引。查询关键词时,可以快速定位包含该词的文档。MySQL B+Tree 索引更适合精确匹配和范围查询,对复杂全文搜索、相关性评分和分词检索不如 ES 合适。
系统与运维基础
Section titled “系统与运维基础”什么是 Docker
Section titled “什么是 Docker”Docker 是容器化技术,可以把应用和依赖打包成镜像,再以容器方式运行。
它解决了“本地能跑,服务器不能跑”的环境一致性问题。
Docker 和虚拟机有什么区别
Section titled “Docker 和虚拟机有什么区别”| 对比项 | Docker | 虚拟机 |
|---|---|---|
| 隔离方式 | 进程级隔离 | 硬件级虚拟化 |
| 启动速度 | 快 | 慢 |
| 资源占用 | 较少 | 较多 |
| 系统内核 | 共享宿主机内核 | 每个虚拟机有完整操作系统 |
| 适用场景 | 应用部署、微服务 | 强隔离、多系统环境 |
Linux 常用命令有哪些
Section titled “Linux 常用命令有哪些”常见命令:
lscdpwdmkdirrmcpmvcattail -f app.loggrep "error" app.logps -eftopdf -hfree -mchmodchown面试时如果结合项目部署经历回答,会比单纯背命令更好。
什么是 REST API
Section titled “什么是 REST API”REST API 是基于 REST 风格设计的接口。
它通常使用 HTTP 协议,通过 URL 表示资源,通过 HTTP 方法表示操作。
这个问题和 Spring 里的 RESTful API 本质相同。
什么是微服务架构
Section titled “什么是微服务架构”微服务是把一个大系统拆成多个小服务,每个服务负责一个相对独立的业务能力。
优点:
- 服务独立部署。
- 技术栈可以更灵活。
- 方便水平扩展。
- 团队边界更清晰。
缺点:
- 服务间调用复杂。
- 分布式事务困难。
- 监控、链路追踪、部署复杂度提高。
什么是 API 网关
Section titled “什么是 API 网关”API 网关是系统入口,负责把外部请求转发到内部服务。
常见功能:
- 路由转发。
- 鉴权。
- 限流。
- 熔断。
- 日志。
- 跨域处理。
项目深挖:Elasticsearch 项目
Section titled “项目深挖:Elasticsearch 项目”如果你的项目重点是 Elasticsearch,面试官很可能会围绕项目继续追问。
可以提前准备这些问题:
| 问题 | 准备方向 |
|---|---|
| 为什么项目要用 ES | MySQL 搜索能力不足、全文检索、分词、排序、性能 |
| 数据怎么同步到 ES | 同步写、异步消息、定时补偿 |
| ES 和 MySQL 数据不一致怎么办 | 重试、补偿任务、最终一致性 |
| 索引怎么设计 | index、mapping、分词器、字段类型 |
| 搜索结果怎么排序 | 相关性评分、业务权重、时间、热度 |
| 查询慢怎么优化 | filter、分页限制、字段选择、索引设计 |
面试时不要只说“我用了 ES”。更好的说法是:
我在项目中用 Elasticsearch 解决全文检索问题。MySQL 更适合事务和结构化查询,但对分词搜索、相关性排序支持有限。所以把需要搜索的数据同步到 ES,通过倒排索引提升搜索效率。项目里还需要考虑 MySQL 和 ES 的数据一致性,比如通过消息队列异步同步,并配合定时任务补偿。
学习能力问题
Section titled “学习能力问题”学习能力问题通常不会太难,但很考验真实感。
常见问题:
- 最近在学什么技术?
- 为什么选择 Java?
- 遇到不会的问题怎么解决?
- 看过哪些技术文档?
- 项目里最有收获的地方是什么?
回答建议:
- 不要只说“我在学 Java”。
- 要说具体学了什么、为什么学、怎么实践。
- 最好能和项目或面试岗位关联起来。
例如:
最近我在补 Redis 和 Elasticsearch。Redis 主要关注缓存穿透、击穿、雪崩以及数据结构的使用场景;Elasticsearch 主要学习倒排索引、DSL 查询和数据同步。因为我的项目里有搜索场景,所以我想把搜索链路和缓存链路都理解得更完整。
如果时间有限,可以按这个顺序准备:
- Java 基础:集合、字符串、异常、反射。
- MySQL:索引、事务、MVCC、索引失效。
- Redis:数据结构、缓存问题、常用命令。
- Spring Boot:IoC、AOP、自动配置、REST API。
- JVM:内存结构、GC、OOM。
- 并发:线程池、锁、volatile、死锁。
- Elasticsearch 项目:倒排索引、DSL、数据同步、搜索优化。
- Docker 和 Linux:能讲清楚部署和常用命令即可。
Java 校招面试不是只背八股。
基础题要能答清楚概念,项目题要能讲清楚自己做了什么、为什么这样做、遇到了什么问题、怎么解决。
这份清单的重点不是一次性背完,而是把每个问题都整理成三层:
一句话结论核心原理项目或使用场景这样回答时会更稳,也更像真的理解过。