
简介这份Java高频面试题PDF面向准备Java后端岗位面试的求职者与初中级开发者聚焦Spring生态与数据库调优两大高频考点。内容系统梳理了Spring Bean生命周期实例化、依赖注入、初始化、销毁、Spring MVC完整执行流程、Spring Boot自动装配原理以及SQL执行计划解读、索引失效场景与优化技巧、MySQL常见索引类型和B树底层结构并延伸至线程池种类与核心参数、拒绝策略等并发知识点。资源包共1个PDF文件约396KB轻量便携适合碎片化复习与面试前速查。目前已有180人学习浏览。读者可借此快速串联Spring框架核心机制与SQL优化思路对照执行计划字段与索引失效清单查漏补缺形成结构化的面试答题框架提升技术表达与实战应对能力。1. 从一份 Java 高频面试题 PDF 说起为什么背完答案还是挂面试间里最尴尬的场景不是被问到完全没听过的名词而是题目你见过、答案你背过面试官追问一句“为什么”就卡壳。很多人手里都有一份流传的 Java 高频面试题 PDF几百道题、分类清晰、答案现成看起来是捷径实际用起来却像黑匣子——输入题目、输出答案中间的理解过程被跳过了。这份 PDF 真正该被当成什么不是背诵手册而是一张知识地图的索引。它告诉你哪些点会被反复考但每个点背后的原理、边界、版本差异得自己补上。这篇文章面向正在准备 Java 后端面试的开发者尤其是工作一到三年、想从“会写业务代码”跨到“能讲清底层机制”的人。我会把这份高频题 PDF 拆成可复现的学习路径哪些题必须手写代码验证、哪些参数要亲手调一遍、哪些坑是面试官最爱追问的。目标很直接——让你下次被追问时能顺着原理往下讲三层而不是背完第一层就没了。2. 把高频题 PDF 拆成可执行的知识模块先分类再动手拿到一份 Java 高频面试题 PDF第一反应不该是从第一页开始背。我一般会先做一次结构拆解把题目按“考察层次”重新归类因为不同层次的题准备方式完全不同。PDF 的原始分类通常是按知识点排的——集合、并发、JVM、Spring、数据库——但面试官提问时是混合着来的所以你得自己建一套索引。2.1 按考察层次给题目打标签记忆层、原理层、设计层记忆层的题答案是事实性的比如“HashMap 默认容量是多少”“ArrayList 和 LinkedList 的区别”。这类题占比不小但单独背它们性价比最低因为面试官很少只问事实一定会往原理层追。原理层的题问的是“为什么这样设计”比如“HashMap 为什么用红黑树而不是 AVL”“ConcurrentHashMap 为什么在 JDK 8 改成 CAS synchronized”。设计层的题最开放比如“让你设计一个本地缓存你会考虑哪些点”它考的是你把前面两层串起来的能力。我的做法是给 PDF 里每道题标一个层级然后统计比例。如果原理层和设计层的题加起来不到一半说明这份 PDF 偏基础你得自己补深度如果超过七成那它更适合当复习提纲而不是入门材料。这个判断决定了你后面花多少时间在动手验证上。2.2 用最小代码验证记忆层结论以 HashMap 扩容为例记忆层的结论最容易记错也最容易被追问翻车。与其死记不如写一段最小代码跑一遍。下面这段代码用来观察 HashMap 的扩容时机和容量变化注意我加了反射读取内部阈值这是理解扩容逻辑的关键。import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; public class HashMapProbe { public static void main(String[] args) throws Exception { MapString, Integer map new HashMap(); // 反射拿到 table 和 threshold 字段观察扩容 Field tableField HashMap.class.getDeclaredField(table); tableField.setAccessible(true); Field thresholdField HashMap.class.getDeclaredField(threshold); thresholdField.setAccessible(true); for (int i 0; i 20; i) { map.put(key i, i); Object[] table (Object[]) tableField.get(map); int threshold (int) thresholdField.get(map); int capacity table null ? 0 : table.length; System.out.printf(size%d, capacity%d, threshold%d%n, map.size(), capacity, threshold); } } }这段代码的逻辑说明HashMap 在第一次 put 时才初始化 table默认容量 16、负载因子 0.75所以阈值是 12。当 size 超过阈值时触发扩容容量翻倍阈值也翻倍。运行后你会看到 capacity 从 0 跳到 16再到 32threshold 从 0 到 12 再到 24。参数说明负载因子 0.75 是空间和时间的折中调大减少扩容但增加哈希冲突调小相反初始容量如果提前知道数据量应该设为预期元素数 / 0.75 1避免多次扩容。这个结论背下来只要一句话但亲手跑一遍面试官问“为什么是 0.75”时你就能从泊松分布和冲突概率的角度答而不是说“书上写的”。2.3 给并发题建一张参数对照表synchronized 与 ReentrantLock并发是高频题里最容易答得含糊的部分。我习惯把关键类做成对照表面试前扫一遍比背大段文字有效。下面这张表覆盖了最常被对比的两个锁参数和边界都列清楚。对比项synchronizedReentrantLock锁获取方式JVM 内置自动释放显式 lock/unlock需 finally 释放可中断不支持lockInterruptibly 支持超时获取不支持tryLock(timeout) 支持公平锁非公平可选公平/非公平条件变量wait/notify 单一可创建多个 Condition锁升级偏向锁→轻量级→重量级无升级概念基于 AQS这张表不是让你背而是让你在回答时能快速定位差异点。比如面试官问“什么时候用 ReentrantLock”你就能从可中断、超时、多条件三个场景切入而不是笼统说“更灵活”。参数上要特别注意ReentrantLock 的公平锁会降低吞吐非公平锁可能造成线程饥饿默认非公平是有性能考虑的。这些边界在 PDF 的答案里往往只有一句话但面试官追问时就是分水岭。3. 用 JVM 和并发两条线串起 PDF 里的硬骨头高频题 PDF 里真正拉开差距的是 JVM 和并发这两块。它们题目多、追问深、光靠背结论必翻车。我的策略是各选一条主线把零散的题挂上去形成能自己推演的链条。3.1 JVM 内存结构从一道“对象在哪分配”追到逃逸分析PDF 里常有一道题“对象一定分配在堆上吗”标准答案是不一定可能栈上分配。但面试官接着会问“什么情况下栈上分配”这就到了逃逸分析。要讲清楚这条链得先理清 JVM 内存结构程序计数器、虚拟机栈、本地方法栈、堆、方法区JDK 8 后是元空间。对象分配的主战场是堆但 JIT 编译器在逃逸分析后可能做标量替换把对象拆成基本类型放在栈上。验证这件事需要动手调参数。下面这组 JVM 参数用来观察逃逸分析的效果注意-XX:PrintEscapeAnalysis在部分版本需要 debug 版 JVM生产环境一般用-XX:DoEscapeAnalysis开启即可。# 开启逃逸分析关闭标量替换做对比 java -XX:DoEscapeAnalysis -XX:-EliminateAllocations -Xmx256m -jar demo.jar # 开启逃逸分析并允许标量替换 java -XX:DoEscapeAnalysis -XX:EliminateAllocations -Xmx256m -jar demo.jar逻辑说明DoEscapeAnalysis控制是否做逃逸分析EliminateAllocations控制是否允许标量替换。两个都开时未逃逸的对象可能被拆散分配在栈上减少堆压力。参数说明-Xmx256m限制堆大小方便观察 GC 频率变化如果对象确实逃逸了比如被返回或存入全局集合逃逸分析不会生效这时调参也没用。常见误用是以为开了逃逸分析所有对象就上栈实际上它只对未逃逸的局部对象生效而且受 JIT 编译阈值影响方法得被调用足够多次才会触发优化。面试时能讲清“逃逸分析是 JIT 的优化手段不是 JVM 规范强制”就已经超过大多数候选人了。3.2 并发工具类用 CountDownLatch 和 CyclicBarrier 做对照实验并发题里 CountDownLatch 和 CyclicBarrier 经常被放在一起问很多人背了“一个减一个加”就完事但面试官会追问使用场景和异常处理。我一般写两个最小 Demo 跑一遍把行为差异刻进记忆。import java.util.concurrent.CountDownLatch; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; public class LatchVsBarrier { public static void main(String[] args) throws Exception { // CountDownLatch主线程等 3 个子任务完成 CountDownLatch latch new CountDownLatch(3); for (int i 0; i 3; i) { new Thread(() - { try { TimeUnit.MILLISECONDS.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println(Thread.currentThread().getName() done); latch.countDown(); }).start(); } latch.await(); System.out.println(all tasks finished); // CyclicBarrier3 个线程互相等待到齐后继续 CyclicBarrier barrier new CyclicBarrier(3, () - System.out.println(barrier action executed)); for (int i 0; i 3; i) { new Thread(() - { try { System.out.println(Thread.currentThread().getName() waiting); barrier.await(); System.out.println(Thread.currentThread().getName() passed); } catch (Exception e) { Thread.currentThread().interrupt(); } }).start(); } } }逻辑说明CountDownLatch 是一次性的计数减到零后所有 await 的线程被释放主线程继续CyclicBarrier 是可循环的每个线程 await 后等其他人到齐然后一起继续还能指定到齐后执行的动作。参数说明CountDownLatch 的构造参数是计数初始值必须和任务数一致调大了会永久阻塞CyclicBarrier 的构造参数是参与线程数如果某个线程在 await 前抛异常其他线程会收到 BrokenBarrierException这是排查时最常忽略的点。常见误用是把 CyclicBarrier 当 CountDownLatch 用结果发现它不能“一个线程等多个”因为它是互相等。面试时能说出“CyclicBarrier 的 await 会抛 BrokenBarrierException需要处理”就是加分项。3.3 线程池参数把 PDF 里的七个参数落到一次压测里线程池的七个参数几乎每份 PDF 都有但背下来和会调是两回事。核心线程数、最大线程数、空闲时间、时间单位、阻塞队列、线程工厂、拒绝策略这七个里最容易翻车的是队列和拒绝策略的组合。我一般用一段代码模拟任务提交观察不同队列下的行为。import java.util.concurrent.*; public class PoolProbe { public static void main(String[] args) { // 核心 2最大 4队列容量 2观察拒绝时机 ThreadPoolExecutor pool new ThreadPoolExecutor( 2, 4, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue(2), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); for (int i 0; i 10; i) { final int id i; try { pool.execute(() - { System.out.println(task id running on Thread.currentThread().getName()); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }); } catch (RejectedExecutionException e) { System.out.println(task id rejected); } } pool.shutdown(); } }逻辑说明任务提交时先看核心线程是否满没满就新建核心线程核心满了进队列队列满了看最大线程是否满没满就新建非核心线程都满了触发拒绝策略。参数说明ArrayBlockingQueue(2)容量为 2所以前 2 个任务占核心线程第 3、4 个进队列第 5、6 个占最大线程第 7 个开始被拒绝。如果把队列换成LinkedBlockingQueue无界队列最大线程数就永远不会被触发任务会一直堆积直到 OOM这是生产环境最常见的坑。拒绝策略里 AbortPolicy 抛异常CallerRunsPolicy 让提交线程自己跑DiscardPolicy 静默丢弃DiscardOldestPolicy 丢最老的。面试时能说清“无界队列会让 maximumPoolSize 失效”比背七个参数名字有用得多。4. 避坑与排查高频题准备里最容易翻车的五件事准备 Java 面试的过程中有些坑几乎每个人都会踩而且踩了之后还以为是题目太难。下面这五条是我自己和身边人反复验证过的按“现象→原因→解决”写清楚。4.1 现象答案背得滚瓜烂熟一追问就断片原因记忆层和原理层混在一起背没有建立因果链。PDF 的答案往往是结论式的比如“HashMap 线程不安全”但没告诉你为什么不安全、什么场景下会出问题。解决每背一个结论强制自己问三个“为什么”然后写最小代码验证。比如“线程不安全”就去跑多线程 put观察死循环或数据丢失亲手复现一次比背十遍都牢。4.2 现象JVM 参数题答得头头是道实际调优时不敢下手原因参数是背的没在真实或模拟环境里调过。比如-Xmn设多大、-XX:SurvivorRatio怎么算光看公式记不住。解决本地起一个 Spring Boot 小服务用-Xmx256m -Xmn128m跑一遍再用jstat -gc观察 Eden、Survivor、Old 区的变化把参数和 GC 日志对应起来。参数说明jstat -gc pid 1000每秒打印一次重点看 YGC 频率和 FGC 次数如果 FGC 频繁且每次回收不多多半是内存泄漏或老年代太小。4.3 现象并发题一写代码就出 bug面试手写环节翻车原因平时只看不写对 API 的异常和边界不熟。比如wait()必须在循环里调用、CountDownLatch.await()要处理中断。解决把 PDF 里所有涉及手写的题列出来每道题在 IDE 里敲一遍跑通再关掉答案重写。重点练生产者消费者、单例双重检查、线程交替打印这三类它们覆盖了锁、等待通知、内存可见性的核心。4.4 现象Spring 题答成配置背诵被问原理就转移话题原因把 Spring 当黑盒用没理解 IoC 和 AOP 的实现。解决写一个最小的 IoC 容器用反射和注解实现 bean 的扫描、实例化、注入几十行代码就能跑通。AOP 则用 JDK 动态代理和 CGLIB 各写一个 Demo对比两者的区别。参数说明JDK 动态代理要求目标类实现接口CGLIB 通过继承实现所以 final 类无法被 CGLIB 代理这是面试常问的边界。4.5 现象数据库题只答索引原理不会看执行计划原因索引结构背得熟但没在真实查询里用过EXPLAIN。解决建一张百万级的模拟表对同一个查询分别加索引和不加索引用EXPLAIN看 type、key、rows 的变化。重点理解 type 从 ALL 到 ref 到 const 的差别以及最左前缀原则在联合索引里的体现。参数说明EXPLAIN的 rows 是预估扫描行数不是精确值但数量级能反映索引是否生效如果 type 是 ALL 且 rows 很大说明走了全表扫描需要检查索引列和查询条件是否匹配。5. 从背题到能讲用费曼技巧把 PDF 榨干最后一章说一个我反复用、也确实有效的技巧把 PDF 里的每道高频题当成你要讲给一个刚入行的同事听。费曼技巧的核心不是复述而是用最少的术语把因果讲通讲不通的地方就是你的知识缺口。具体做法是挑一道题比如“ThreadLocal 为什么会内存泄漏”先合上 PDF用白板或空白文档写下你的解释然后对照三个标准检查有没有说清 ThreadLocalMap 的 key 是弱引用、value 是强引用有没有说清为什么 key 弱引用还会泄漏有没有说清remove()在什么时机调用。任何一条卡住就回去补补完再讲一遍。我一般会把这种讲解录成三分钟的语音回听时专挑自己含糊的地方。含糊往往出现在两个位置一是版本差异比如 JDK 8 和 JDK 17 在 GC 或集合实现上的变化二是边界条件比如“大多数情况”和“一定”的区别。面试官追问的往往就是这两处。下面这张表是我用来检查讲解质量的清单每道题过一遍比刷十遍 PDF 有用。检查项合格标准常见不合格表现因果链能说出至少三层为什么只答结论追问就重复结论版本边界能指出 JDK 版本差异把 JDK 8 的行为当成所有版本反例能举出一个失效场景只说“一般”“通常”参数能说出关键参数和默认值参数名记混或默认值说错手写能默写出核心代码结构只记得 API 名字写不出逻辑这个清单不是让你逐条背而是讲解时自然覆盖。我自己的血泪经验是早期准备时把 PDF 刷了三遍结果面试被问“ConcurrentHashMap 的 size() 怎么实现的”直接卡住因为 PDF 只写了“线程安全”没写 size 的实现细节。后来我改用讲解法每道题都逼自己讲到能回答“怎么实现的”这一层才真正稳下来。还有一点别等到面试前一周才开始讲平时每学一个模块就讲一次讲完记下卡壳点那些就是你的复习重点。希望帮到你。本文还有配套的精品资源点击获取