简介这是一份面向Java初学者与应届求职者的面试题汇总文档覆盖从校园或培训阶段走向技术面试所需的核心考点帮助读者在有限时间内系统梳理知识脉络、查漏补缺。资源以单个docx文件打包压缩包约155KB内容按十八个模块组织包括Java基础、多线程、反射、对象拷贝、JavaWeb、异常、网络、设计模式、Spring/Spring MVC、Spring Boot/SpringCloud、Hibernate、MyBatis、RabbitMQ、Kafka、Zookeeper、MySQL、Redis与JVM共收录208道常见面试题并附参考答案。其中Java基础部分对JDK与JRE的区别、与equals的差异、hashCode与equals的关系、final关键字作用等高频问题给出了代码示例与源码解读便于理解底层原理。目前已有616人学习适合需要一份权威面试清单、按模块逐项复习的初级Java人员参考。1. 从一份 208 题的 Java 初级面试题库说起它到底能帮你解决什么如果你正在准备 Java 初级岗位的面试或者刚带完一个培训班、想给学员找一份能直接背、能直接查、能直接对着代码验证的题库那这份《Java 初级面试题汇总带答案》大概率能省掉你不少翻博客的时间。它把内容拆成 18 个模块——Java 基础、多线程、反射、对象拷贝、JavaWeb、异常、网络、设计模式、Spring/Spring MVC、Spring Boot/SpringCloud、Hibernate、MyBatis、RabbitMQ、Kafka、Zookeeper、MySQL、Redis、JVM一共 208 道题每道题都配了答案部分题还带了可运行的代码片段。它适合两类人一类是校招或转行刚入行的开发者需要一份覆盖面够广的清单来查漏补缺另一类是工作一两年、想跳槽但基础概念已经模糊的人拿它当复习提纲。不适合指望靠背题拿高薪的人——初级题就是初级题答案给的是结论和最小示例深挖还得自己补。下面我按“怎么用、怎么验证、坑在哪”的顺序把这份资源拆开讲。2. 十八个模块怎么排优先级从 Java 基础到 JVM 的复习路线拿到一份 208 题的文档最忌讳从第一页顺着背到最后一页。初级面试的提问密度是不均匀的Java 基础、集合、多线程这三块几乎每场必问Spring 和 MySQL 次之Zookeeper、Kafka 这类中间件在初级岗里出现频率明显偏低。所以第一步不是背是排优先级。2.1 按面试出现频率给模块分三档我把这 18 个模块按初级岗的实际提问频率分成三档你可以对照自己的薄弱项决定投入时间档位模块建议投入理由高频Java 基础、多线程、集合在基础模块内、MySQL、Spring/Spring MVC60% 时间几乎每场必问且追问深中频JVM、Redis、MyBatis、设计模式、异常、网络30% 时间常作为加分项或二面内容低频RabbitMQ、Kafka、Zookeeper、Hibernate、SpringCloud、对象拷贝、反射10% 时间初级岗问得浅知道概念即可这个分档不是绝对的取决于你投的岗位方向。比如投中间件团队Kafka 和 Zookeeper 的权重就要往上提。但对大多数初级岗来说把高频档吃透比每个模块都浅尝一遍要划算得多。2.2 用“概念—代码—追问”三步法过每一题这份资源的答案是“结论式”的比如“ 对于基本类型是值比较对于引用类型是引用比较”。光背这句话面试官换个问法你就卡壳。我一般会按三步过一道题第一步读答案把结论用自己的话复述一遍。第二步把答案里的代码片段敲进 IDE 跑一遍看输出是否和文档一致。第三步自己给自己提一个追问。比如和equals这题追问就是“为什么 String 的 equals 返回 true 而自定义对象的 equals 返回 false”。以文档里和equals的示例为例你可以直接建一个测试类验证public class EqualsTest { public static void main(String[] args) { String x string; String y string; String z new String(string); // x 和 y 都指向常量池中的同一个 string System.out.println(x y); // true // z 是 new 出来的在堆上另开辟了空间 System.out.println(x z); // false // equals 被 String 重写为值比较 System.out.println(x.equals(y)); // true System.out.println(x.equals(z)); // true } }这段代码的关键在于理解 JVM 的内存分配字面量string会进常量池new String(string)则在堆上创建新对象。比较的是引用地址equals在 String 中被重写为逐字符比较。跑一遍这个例子比背十遍结论都管用。2.3 给每个模块配一个“最小验证工程”光看文档容易产生“我懂了”的错觉。我的习惯是给每个高频模块建一个最小的 Maven 工程把文档里的代码片段放进去跑。比如多线程模块文档里提到了synchronized锁升级、ThreadLocal、线程池的七种创建方式这些都可以写一个main方法验证。以线程池为例文档列出了newFixedThreadPool、newCachedThreadPool等创建方式你可以写一段代码观察不同线程池的行为差异import java.util.concurrent.*; public class ThreadPoolDemo { public static void main(String[] args) throws Exception { // 固定 2 个线程队列无界任务超过 2 个会排队 ExecutorService fixed Executors.newFixedThreadPool(2); for (int i 0; i 5; i) { final int taskId i; fixed.submit(() - { System.out.println(fixed task taskId on Thread.currentThread().getName()); try { Thread.sleep(500); } catch (InterruptedException e) {} }); } fixed.shutdown(); fixed.awaitTermination(10, TimeUnit.SECONDS); // 缓存线程池空闲 60 秒回收适合大量短任务 ExecutorService cached Executors.newCachedThreadPool(); for (int i 0; i 5; i) { final int taskId i; cached.submit(() - System.out.println(cached task taskId on Thread.currentThread().getName())); } cached.shutdown(); } }跑完你会直观看到fixed池里始终只有两个线程名在交替cached池则可能为每个任务开新线程。文档里说的“无界队列”“60 秒回收”这些参数跑一遍就有体感了。参数上newFixedThreadPool(int nThreads)的nThreads就是核心线程数也是最大线程数队列用的是LinkedBlockingQueue默认容量Integer.MAX_VALUE这也是它容易 OOM 的原因后面避坑章节会细说。3. 把答案变成能跑通的代码基础与多线程模块的验证方法文档里 Java 基础和多线程两个模块的代码片段最多也最值得动手验证。这一章挑几个典型题讲清楚怎么从“看懂答案”走到“能自己写出来”。3.1 hashCode 与 equals 的契约用“通话”和“重地”验证文档里有一道很经典的题两个对象的hashCode()相同equals()一定为 true 吗答案是不一定并给了通话和重地这两个字符串作为例子。这两个词的 hashCode 相同但 equals 为 false。你可以直接跑public class HashCodeDemo { public static void main(String[] args) { String str1 通话; String str2 重地; // 两个不同字符串的 hashCode 碰撞 System.out.println(String.format(str1:%d | str2:%d, str1.hashCode(), str2.hashCode())); System.out.println(str1.equals(str2)); // false } }输出会是两个相同的哈希值和一个false。这背后的原理是hashCode 是散列函数不同输入可能得到相同输出哈希碰撞而 equals 才是判断相等性的最终依据。面试时如果只答“hashCode 相同 equals 不一定 true”面试官可能追问“那为什么重写 equals 必须重写 hashCode”这时候你要能说出如果两个对象 equals 相等但 hashCode 不同它们在 HashMap 里会被放到不同的桶导致逻辑错误。3.2 String、StringBuffer、StringBuilder 的性能差异实测文档第 7 题讲了这三个类的区别结论是 String 不可变、StringBuffer 线程安全、StringBuilder 非线程安全但性能高。这个结论可以量化验证public class StringPerfDemo { public static void main(String[] args) { int loop 100000; // String 拼接每次生成新对象 long t1 System.currentTimeMillis(); String s ; for (int i 0; i loop; i) { s a; } long t2 System.currentTimeMillis(); // StringBuilder 单线程拼接 StringBuilder sb new StringBuilder(); for (int i 0; i loop; i) { sb.append(a); } long t3 System.currentTimeMillis(); // StringBuffer 线程安全拼接 StringBuffer sbf new StringBuffer(); for (int i 0; i loop; i) { sbf.append(a); } long t4 System.currentTimeMillis(); System.out.println(String: (t2 - t1) ms); System.out.println(StringBuilder: (t3 - t2) ms); System.out.println(StringBuffer: (t4 - t3) ms); } }十万次循环下String 的耗时通常是 StringBuilder 的几十倍甚至上百倍StringBuffer 因为加了synchronized会比 StringBuilder 略慢。这个实测数据比背结论有说服力得多。参数上循环次数可以调但别调到百万级String 拼接会慢到让你以为程序卡死。3.3 线程状态与 sleep/wait 的验证文档第 40、41 题讲了线程状态和sleep()与wait()的区别。sleep不释放锁、wait释放锁这个区别用代码验证最直观public class WaitSleepDemo { public static void main(String[] args) throws Exception { Object lock new Object(); Thread t1 new Thread(() - { synchronized (lock) { System.out.println(t1 拿到锁准备 wait); try { lock.wait(); } catch (InterruptedException e) {} System.out.println(t1 被唤醒重新拿到锁); } }); Thread t2 new Thread(() - { synchronized (lock) { System.out.println(t2 拿到锁准备 notify); lock.notify(); System.out.println(t2 调用 notify 后仍持有锁); } }); t1.start(); Thread.sleep(100); // 确保 t1 先进入 wait t2.start(); } }跑这段代码你会看到t1 调用wait()后释放了锁t2 才能进入同步块t2 调用notify()后并没有立即释放锁而是等同步块执行完才释放t1 才被唤醒。如果把wait()换成Thread.sleep()t1 会一直持有锁t2 根本进不来。这个对比就是面试官想听到的“释放锁”的实际含义。4. 避坑与排查用这份题库复习时最容易翻车的五个点这份资源本身质量不错但使用方式不对很容易出现“背了 208 题还是过不了面试”的情况。下面五条是我见过和踩过的坑。4.1 只背结论不跑代码面试追问就露馅现象把文档里的答案背得滚瓜烂熟面试官问“为什么”就答不上来。原因文档给的是结论比如“ArrayList 扩容增加 50%”但没解释为什么是 50% 而不是 100%。解决每背一个结论强迫自己补一个“为什么”。ArrayList 扩容 50% 是因为oldCapacity (oldCapacity 1)位运算右移一位相当于除以 2这样在空间和扩容频率之间取平衡。这类追问在初级岗二面很常见。4.2 把初级题当高级题背浪费时间在低频模块现象花大量时间背 Zookeeper 的 ZAB 协议、Kafka 的 ISR 机制结果面试根本没问。原因没区分岗位级别初级岗的中间件问题通常停留在“是什么、怎么用”。解决按第 2 章的分档表分配时间低频模块知道基本概念即可把省下的时间用来把 HashMap 的扩容、线程池参数、Spring Bean 生命周期这些高频追问点吃透。4.3 代码片段直接复制忽略 JDK 版本差异现象文档里的代码在自己机器上跑报错或结果不一致。原因部分 API 在不同 JDK 版本行为不同比如String的hashCode算法在极端情况下、HashMap的树化阈值在 JDK 8 前后有变化。解决跑代码前先确认 JDK 版本初级面试目前主流是 JDK 8 和 JDK 11文档里的示例基本兼容但涉及集合扩容、锁升级的内容要以 JDK 8 为准。用java -version确认必要时装多个版本切换。4.4 线程池创建方式记混参数说不清现象面试问“线程池有哪几种创建方式”答出七种但说不清newFixedThreadPool和newCachedThreadPool的队列区别。原因文档列了七种方式但没强调它们底层都是ThreadPoolExecutor的封装。解决记住核心参数corePoolSize、maximumPoolSize、keepAliveTime、workQueue、threadFactory、handler然后反推每种创建方式对应的参数组合。比如newFixedThreadPool(n)就是核心最大n队列用无界LinkedBlockingQueuenewCachedThreadPool()就是核心 0、最大Integer.MAX_VALUE、队列用SynchronousQueue、空闲 60 秒回收。4.5 忽略“对象拷贝”和“反射”模块结果被问到现象觉得反射和对象拷贝是高级内容跳过不看结果面试官问“深拷贝和浅拷贝的区别”“反射怎么获取私有方法”。原因这两个模块在初级岗里确实问得少但一旦问到就是区分度题。解决至少掌握浅拷贝Object.clone()是浅拷贝、深拷贝序列化或递归 clone、反射获取Class对象的三种方式Class.forName、对象.getClass()、类.class以及getDeclaredMethod和setAccessible(true)的用法。不用深挖但要知道。5. 从 208 题到面试通过一套可复用的自测与追问技巧背完题库只是第一步真正拉开差距的是“自测”和“追问”。我一般会用一个笨办法把 208 道题当成 208 个面试官每道题自己先答一遍录音然后回放听哪里卡壳。卡壳的地方就是薄弱点回去补代码验证。具体操作上我会按模块做一张自测表每道题标记三个状态能流畅答出、能答但磕巴、答不出。只刷“答不出”和“磕巴”的题流畅的题每周抽一次快速过。这样 208 题的实际复习量会压缩到 60 到 80 题效率高很多。追问技巧方面我总结了一个模板任何一道题都问自己三个问题——它是什么、它为什么这样设计、它和相似概念的区别是什么。以HashMap为例它是什么基于哈希表的 Map 实现、为什么这样设计数组链表红黑树兼顾查询和插入效率、和Hashtable的区别线程安全、null 支持、扩容方式。这三个问题答得出来面试官基本问不倒你。还有一个容易被忽略的点文档里的答案有些是“一句话结论”比如“BIO 是同步阻塞、NIO 是同步非阻塞、AIO 是异步非阻塞”。这种题面试官很可能让你举例说明。我的习惯是给每个概念配一个生活化类比BIO 像排队打饭一个人不打完后面的人干等NIO 像取号机取完号可以去干别的叫到号再回来AIO 像外卖下单后不用管送到了通知你。类比不一定严谨但能帮你在紧张时快速组织语言。最后说一个我自己的教训。早年我复习面试题总喜欢从头到尾刷一遍刷完就扔结果面试时遇到原题还是答不利索。后来我改成“每道题必须能写出最小验证代码”哪怕只是三行System.out.println写出来和看一遍的效果完全不同。从那以后我每次复习任何题库都强制自己至少跑通其中 30% 的代码示例剩下的 70% 也要能口述出验证思路。这个习惯帮我省掉了大量“以为自己会了”的幻觉时间。希望帮到你。本文还有配套的精品资源点击获取