2021 Java面试真题深度解析:技术要点与实战策略
一、JVM基础与内存管理
真题1:JVM内存模型由哪些区域组成?各区域的作用是什么?
JVM内存模型分为方法区、堆、虚拟机栈、本地方法栈和程序计数器。堆是线程共享区域,存储对象实例和数组,是垃圾回收(GC)的主要区域;方法区存储类信息、常量、静态变量等,JDK8后由元空间(Metaspace)替代永久代;虚拟机栈为线程私有,每个方法执行时创建栈帧,存储局部变量表、操作数栈等。例如,int a = 10;的局部变量a存储在栈帧的局部变量表中。
真题2:如何判断对象是否存活?引用计数法与可达性分析法的区别是什么?
引用计数法通过统计对象被引用的次数判断存活,但无法处理循环引用问题;可达性分析法以GC Roots(如虚拟机栈中的对象引用、方法区中的静态变量)为起点,通过引用链判断对象是否可达。Java采用后者,例如:
Object obj1 = new Object(); // obj1为GC Roots可达对象Object obj2 = new Object();obj1.ref = obj2; obj2.ref = obj1; // 循环引用,但若obj1无其他引用,仍会被回收
真题3:常见的垃圾回收算法有哪些?各适用于什么场景?
- 标记-清除:标记无用对象后直接清除,产生内存碎片,适用于老年代。
- 复制算法:将内存分为两块,存活对象复制到另一块后清理原区域,无碎片但空间利用率低,适用于新生代(Eden:Survivor=8
1)。 - 标记-整理:标记后整理存活对象到一端,清理边界外内存,适用于老年代。
- 分代收集:结合上述算法,新生代用复制算法,老年代用标记-清除或标记-整理。
二、Java并发编程与多线程
真题4:synchronized与ReentrantLock的区别是什么?
- 锁的实现:synchronized是JVM内置关键字,ReentrantLock是API实现的锁。
- 公平性:synchronized为非公平锁,ReentrantLock可配置公平/非公平模式。
- 功能扩展:ReentrantLock支持条件变量(Condition)、可中断锁、超时获取锁等。例如:
Lock lock = new ReentrantLock();Condition condition = lock.newCondition();lock.lock();try {while (conditionNotMet) {condition.await(); // 释放锁并等待}} finally {lock.unlock();}
真题5:volatile关键字的作用是什么?如何保证可见性和有序性?
volatile修饰的变量保证每次读写都直接操作主内存,避免线程工作内存中的缓存不一致(可见性)。通过插入内存屏障(Memory Barrier)禁止指令重排序(有序性)。例如,双重检查锁定(DCL)单例模式中需用volatile防止指令重排序导致对象未初始化:
public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton(); // 防止指令重排序}}}return instance;}}
真题6:线程池的核心参数有哪些?如何配置合理参数?
线程池参数包括核心线程数(corePoolSize)、最大线程数(maximumPoolSize)、空闲线程存活时间(keepAliveTime)、任务队列(workQueue)和拒绝策略(RejectedExecutionHandler)。配置建议:
- CPU密集型任务:核心线程数≈CPU核心数(避免过多线程竞争CPU)。
- IO密集型任务:核心线程数可适当增大(如CPU核心数*2),利用线程等待IO的时间处理其他任务。
- 队列选择:无界队列(如LinkedBlockingQueue)可能导致OOM,建议使用有界队列(如ArrayBlockingQueue)配合拒绝策略(如CallerRunsPolicy)。
三、Spring框架与源码解析
真题7:Spring Bean的生命周期是怎样的?
- 实例化:通过反射或工厂方法创建Bean实例。
- 属性赋值:依赖注入(DI)设置Bean的属性。
- 初始化前:调用
BeanPostProcessor的postProcessBeforeInitialization方法。 - 初始化:执行
InitializingBean的afterPropertiesSet或自定义init-method。 - 初始化后:调用
BeanPostProcessor的postProcessAfterInitialization方法(如AOP代理在此生成)。 - 销毁:容器关闭时调用
DisposableBean的destroy或自定义destroy-method。
真题8:Spring AOP的实现原理是什么?
Spring AOP基于动态代理,JDK动态代理(接口代理)和CGLIB(子类代理)。当Bean实现接口时使用JDK代理,否则使用CGLIB。例如:
@Aspect@Componentpublic class LoggingAspect {@Before("execution(* com.example.service.*.*(..))")public void logBefore(JoinPoint joinPoint) {System.out.println("Method called: " + joinPoint.getSignature().getName());}}
代理对象在方法调用前后织入切面逻辑。
真题9:Spring事务的传播行为有哪些?
- REQUIRED:默认行为,加入当前事务,若无则新建。
- SUPPORTS:支持当前事务,若无则以非事务方式执行。
- MANDATORY:必须存在事务,否则抛出异常。
- REQUIRES_NEW:新建事务,挂起当前事务(如日志记录需独立提交)。
- NOT_SUPPORTED:以非事务方式执行,挂起当前事务。
- NEVER:以非事务方式执行,若存在事务则抛出异常。
- NESTED:嵌套事务,子事务回滚不影响父事务(需数据库支持保存点)。
四、数据库与SQL优化
真题10:MySQL的索引类型有哪些?如何优化索引使用?
- 普通索引:最基本的索引类型。
- 唯一索引:列值必须唯一,允许NULL值。
- 主键索引:特殊的唯一索引,不允许NULL值。
- 联合索引:多列组合索引,遵循最左前缀原则。例如,索引
(a,b,c)可优化a=1、a=1 AND b=2,但无法优化b=2。 - 覆盖索引:查询列全部在索引中,避免回表。例如:
CREATE INDEX idx_name_age ON user(name, age);SELECT name, age FROM user WHERE name = 'Alice'; -- 使用覆盖索引
真题11:事务的隔离级别有哪些?各解决什么问题?
- 读未提交(Read Uncommitted):可能读到未提交的数据(脏读)。
- 读已提交(Read Committed):解决脏读,但可能不可重复读。
- 可重复读(Repeatable Read):解决不可重复读,但可能幻读(MySQL通过MVCC和间隙锁解决)。
- 串行化(Serializable):最高隔离级别,通过加锁避免并发问题,但性能最低。
五、总结与建议
2021年Java面试题聚焦底层原理(如JVM、并发)、框架源码(如Spring)和工程实践(如线程池配置、SQL优化)。建议开发者:
- 深入原理:理解GC算法、锁升级过程等底层机制。
- 结合源码:阅读Spring、Netty等框架的核心代码。
- 实战演练:通过LeetCode、设计模式项目提升编码能力。
- 关注更新:学习Java 15+的新特性(如密封类、记录类)。
掌握这些要点,不仅能应对面试,更能提升实际开发中的问题解决能力。