
1. 2026年3月Java基础面试题为什么还要认真过一遍说实话每年三月份都是程序员跳槽和春招最集中的时间。最近我帮几个朋友做了模拟面试聊了十几轮下来最明显的感受是Java基础面试题这东西永远有人觉得简单也永远有人在上面栽跟头。很多人的状态是框架八股背得滚瓜烂熟一问到HashMap的扩容时机、String到底是不是不可变、synchronized锁的到底是什么就开始含糊其辞。而面试官恰恰最喜欢从这些题目往下深挖因为你基础题答不好他会默认你对上层框架的理解也是空中楼阁。这篇文章是一份持续更新的Java基础面试题汇总核心覆盖语法、集合、面向对象、异常、泛型、并发和JVM基础这几大块。不是简单罗列答案而是把每道题背后“为什么这么考”和“怎么答才算到位”一并讲清楚同时补充我实际模拟面试和招聘过程中见过的典型错误。适合正在准备校招、社招或转岗Java开发的人阅读也适合那些自认为基础不错、想快速自查的人。建议你带着两个问题去读这道题考察的知识点是什么如果面试官追问两层我还能不能接得住2026年这个时间点尤其要注意一点面试官对“背题”越来越反感。他们会故意把题目变个场景比如不直接问“HashMap底层结构”而是问“如果有200个元素频繁put和get你会怎么选型”。这种问法就需要你把基础原理讲透而不是只记结论。所以这份汇总里的每道题我都尽量给出了底层原理和答题方向而不是单纯背一句标准答案。2. Java基础语法与常用API高频题2.1 基本类型、包装类与缓存机制最容易“答着答着就翻车”的细节先看一个我面试真实问过的题Integer a 127; Integer b 127; System.out.println(a b); // true Integer c 128; Integer d 128; System.out.println(c d); // false很多候选人看到Integer就条件反射地说“对象比较要用equals”但问他为什么127是true、128是false时就卡住了。其实这背后是包装类的缓存机制Integer在-128~127范围内会使用IntegerCache直接返回缓存对象所以a和b指向同一个对象超出范围则新建对象c和d是不同引用用比较自然为false。这道题真正想考察的是你是否理解自动装箱、拆箱和对象缓存而不只是会背一句“比较地址”。顺着这个方向我还建议你把基本类型和包装类的对应关系、默认值、占用大小一起复习了因为面试官很可能随手画个表格让你填。基本类型字节数默认值包装类缓存范围byte10Byte-128~127short20Short-128~127int40Integer-128~127long80LLong-128~127float40.0fFloat无double80.0dDouble无char2\u0000Character0~127boolean不一定falseBooleantrue/false实际面试里还有个高频变形题long和float到底谁大很多人的第一反应是long有64位float是32位所以long大。但float的表示范围远大于long因为float用指数位表示范围所以两者比较时要分清“存储大小”和“数值范围”两个概念。补充一个实操心得复习这块最好的方式不是背表格而是自己写一段自动装箱的代码把Integer在不同数值范围内的和equals结果都打印出来。踩过一次坑后这类题基本就再也不会错了。2.2 String、StringBuilder、StringBuffer三兄弟背后的底层逻辑Java基础面试题里String相关题目出现频率极高几乎可以说是“必考题”之首。常规问题包括String为什么不可变、String常量池在哪里、String s new String(abc)创建了几个对象、StringBuilder和StringBuffer有什么区别。先说最核心的不可变性。String类内部用private final char value[]或者JDK 9之后的byte[]存储字符并且String类本身被final修饰所有修改字符串的方法都是生成新对象而不是改变原有对象。不可变的好处有三个线程安全、支持字符串常量池缓存、适合作为HashMap的key。面试官问“不可变有什么好处”时建议从这三个角度展开会比单说一句“安全”更有说服力。再聊经典的“创建了几个对象”问题String s1 abc; String s2 new String(abc);第一行如果常量池中没有“abc”会在常量池中创建一个对象。第二行会在堆上创建一个String对象同时“abc”会先检查常量池如果不存在也会创建所以这句话可能创建1个或2个对象具体取决于常量池中是否已经有“abc”。面试时一定要分情况回答直接说“创建两个对象”会被认为考虑不周。关于字符串拼接我实际测试过一段代码String s a b c;编译期会直接优化成abc这是编译期常量折叠。但如果拼接中包含变量比如String s a b c;编译后会变成new StringBuilder(a).append(b).append(c).toString()。这也是面试官常问“为什么循环拼接字符串性能差”的原因每次循环都可能产生新的StringBuilder和String对象。正确做法是循环外用StringBuilder并且预估容量后调用ensureCapacity减少扩容复制。至于StringBuilder和StringBuffer的区别大家熟知的答案是StringBuffer的方法加了synchronized线程安全但性能稍低StringBuilder线程不安全但更快。我建议再补一句在方法内部局部变量场景下两者线程安全属性其实没有区别但面试官通常希望你先答出核心区别再补一句“单线程环境优先用StringBuilder”就够了。2.3 集合框架高频题ArrayList、LinkedList与HashMap的底层实现集合框架是Java基础面试的重灾区因为能考的细节实在太多了。最常见的开场题目是“ArrayList和LinkedList有什么区别”这题看起来简单但至少要能从三个维度回答底层结构、查找/插入性能、内存占用。维度ArrayListLinkedList底层结构动态数组双向链表随机访问O(1)按索引直达O(n)需要遍历尾部插入均摊O(1)扩容时有复制成本O(1)中间插入/删除O(n)需要挪动元素O(n)但不需要挪动只需要改指针内存占用底层数组可能预留空位每个节点额外存储prev和next引用我见过太多人直接就答“ArrayList查询快、增删慢LinkedList增删快、查询慢”这个说法其实不够严谨如果按下标插入到中间LinkedList同样要先找到那个位置复杂度也是O(n)而在尾部插入ArrayList并不慢。更好的回答是先给结论再说明复杂度来源最后补一句“实际项目中ArrayList是绝对主流LinkedList的使用场景非常少”。这一句往往会成为加分项说明你有真实工程经验。HashMap更是必问中的必问。建议按下面这条线准备底层结构是数组加链表加红黑树在JDK 8中链表长度超过8且数组长度超过64时树化默认初始容量16负载因子0.75扩容阈值是容量乘以负载因子即12每次扩容为原来的两倍扩容时重新计算元素位置。还要了解hash方法的作用让高位也参与扰动减少哈希碰撞。面试官最爱追问的连环题是“为什么链表转红黑树的阈值是8为什么加载因子是0.75”前者可以从泊松分布角度解释官方注释提到在随机哈希下链表长度到8的概率已经极低树化是为了应对极端哈希冲突后者是空间和时间成本的折中0.75意味着空间用满四分之三就开始扩容避免哈希冲突过密。这里提醒一个坑网上很多老版本的资料还在讲“HashMap多线程扩容会形成环形链表导致死循环”这个问题在JDK 8之后其实已经被修复但多线程下依然会因为丢失数据等问题而不安全。回答时建议说清楚JDK 7在并发扩容时可能产生环JDK 8解决了环问题但并发问题依然存在所以并发场景要用ConcurrentHashMap。如果只凭记忆说“HashMap是线程不安全的”会被追问到说不出原理那就很尴尬。3. 面向对象、异常与泛型考官真正在看什么3.1 封装、继承、多态怎么答出亮点“Java面向对象三大特性”是看起来最简单、实际最容易被问出深度的题目。大部分人都能说出封装、继承、多态的定义但面试官真正想看的是你能不能把多态讲得深入。我的建议是多态的答案至少应该拆成两层。第一层是定义多态分为编译时多态和运行时多态前者通过方法重载实现后者通过方法重写和父类引用指向子类对象实现。第二层是运行时多态的底层支持Java通过方法表或虚方法分派机制在运行时根据对象实际类型确定调用哪个方法。换句话说编译期看的是引用类型运行期看的是实际对象类型。举个例子class Animal { void speak() { System.out.println(Animal); } } class Dog extends Animal { Override void speak() { System.out.println(Dog); } } Animal a new Dog(); a.speak(); // 输出 Dog这段代码展示的就是典型的运行时多态。面试官如果继续追问“成员变量有没有多态”答案是没有成员变量是静态分派编译期就绑定了引用类型的字段。我曾问过几个候选人这个问题有一半人都想当然地说变量也有多态其实只要看a.kind这样的访问逻辑就能验证能够说清楚这一点的人通常对JVM方法调用机制有更扎实的理解。除了三大特性接口和抽象类的区别也是高频追问。核心区别是抽象类可以有实例字段和构造方法也能提供部分实现接口则更多是一种能力约定从Java 8开始可以有default和static方法但本质上仍然不能保存实例状态。选型时我的经验是如果是“is-a”关系且有公共代码需要复用用抽象类如果是“can-do”关系或需要跨继承树实现同一行为用接口。答题结构上我推荐“结论先行、逐层展开”的方式先说“多态是允许不同类的对象对同一消息做出不同响应”再说“底层靠方法表分派”最后给一个小例子。这样既展示基础也展示深度比倒过来从例子讲起要清晰得多。3.2 异常体系受查与非受查的边界Java异常这块很多候选人能说出Exception和Error但再往下问就乱了。实际上我建议你在脑子里把继承体系理成一条链Throwable是所有异常和错误的父类下面分两大分支Error和ExceptionException又分为受检异常checked exception和运行时异常unchecked RuntimeException。维度受检异常运行时异常编译期检查必须捕获或声明抛出不强制捕获父类Exception非RuntimeException子类RuntimeException常见例子IOException、SQLException、ClassNotFoundExceptionNullPointerException、IllegalArgumentException、ArrayIndexOutOfBoundsException设计意图可恢复的外部异常调用者应该处理程序Bug或不可恢复状态面试里有一个经典讨论题“Spring事务默认情况下为什么会自动回滚”这题和异常体系直接相关Spring默认只对运行时异常回滚受检异常默认不触发回滚因为受检异常被认为业务层面可以处理的异常。很多人只知道“默认回滚RuntimeException”却不知道为什么其实本质就是对异常分类的理解不够。还有一个实操层面的考点是try-with-resources。从Java 7开始凡是实现了AutoCloseable的资源都可以通过这个语法自动关闭try (BufferedReader reader new BufferedReader(new FileReader(test.txt))) { System.out.println(reader.readLine()); } catch (IOException e) { e.printStackTrace(); }这个语法比传统在finally里手动close更简洁而且能正确处理“关闭时又抛异常”的复杂场景。面试时被问到流关闭优先展示try-with-resources再补充说明资源类要实现AutoCloseable接口会显得经验比较新。我踩过的一个坑是有人背了一大堆异常类的名字却不知道什么时候该自己定义异常。这里给个实操建议自定义异常通常继承RuntimeException并带上一个有效的错误码方便上层统一捕获和处理而不要在业务代码里频繁抛出受检异常否则会让方法签名变得很臃肿。3.3 泛型类型擦除与PECS泛型这块基础面试通常不会考得太深但“类型擦除”和“PECS”两个点是必要的护城河一旦问中就是拉分题。类型擦除的意思是Java泛型的信息只存在于编译期编译后会擦除为原始类型或边界类型。比如ListString list new ArrayList(); list.add(hello); String value list.get(0);编译后add和get相关的地方实际会插入必要的类型转换。这也是为什么“泛型不能用于创建数组”的原因数组需要具体类型信息来保证运行时类型安全而泛型的类型信息在运行时已经不存在了。PECS是“Producer Extends, Consumer Super”的缩写来自《Effective Java》。实际使用时如果要从一个泛型集合中读取元素作为“生产者”用? extends T如果要写入元素作为“消费者”用? super T。举个例子public void copy(List? extends Number src, List? super Number dest) { for (Number n : src) { dest.add(n); } }这段代码里src只读不写所以用extendsdest只写不读所以用super。面试时能写对Collection? super T往里面添加元素、从Collection? extends T往外读元素就至少证明你真正用过泛型通配符而不只是背过名字。需要注意一点JDK 10之后引入了var很多人在局部变量里用var写泛型类比如var list new ArrayListString();这会减少代码冗余但面试题里我仍建议优先用显式类型因为笔试环境对版本支持不确定显式声明反而更稳。4. 并发与JVM基础基础题里的进阶分4.1 线程创建方式与生命周期并发题目在Java基础面试里权重越来越高尤其是一些中小公司基础面试题汇总里并发可能占四分之一。第一个高频题就是“创建线程有几种方式”。这里我给一个不容易丢分的回答继承Thread类重写run()方法。实现Runnable接口传给Thread构造器。实现Callable接口配合FutureTask获取返回值。使用线程池ExecutorService内部本质还是Runnable或Callable。我推荐的答题结构是先说官方没有硬性规定几种但主流的实现方式有四类然后强调“真正执行任务的核心逻辑都是run()方法方式不同只是任务来源和结果获取方式不同”。这样既回答了问题又展示了你对本质的理解。还有一个必问点为什么启动线程用start()而不是直接调用run()。答案的核心是start()会让JVM创建一个新线程并在新线程中执行run()方法的逻辑直接调用run()只会在当前线程里把它当作普通方法执行没有多线程效果。面试官如果继续追问“start()能不能重复调用”答案是会抛出IllegalStateException因为线程状态已经不为0。线程生命周期也是常客从Thread.State枚举来看有NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED六种。注意这里没有单独叫RUNNING的状态运行中也被归到RUNNABLE很多候选人会把RUNNABLE误解成只有就绪状态这是需要纠正的细节。我实际面试中还喜欢追问一个场景题“IO密集型的任务怎么确定线程池大小?”这其实开始超纲了但基础面试如果能把“CPU密集型用CPU核数1IO密集型用更多线程去阻塞等待”这个思路说出来会显得很有工程意识。4.2 synchronized与volatile别只背区别要能讲出原理volatile和synchronized的区别属于那种“背了无数遍、一紧张就说不全”的题目。我的建议是把答案收敛成三个维度作用层面、原子性层面、适用场景层面。先说volatile。它保证了两件事可见性和有序性。所谓可见性就是一个线程修改了变量其他线程能立刻看到最新值因为volatile变量读写会插入内存屏障禁止指令重排序并让修改强制刷回主存。但它不保证原子性比如count这种“读-改-写”操作即使变量是volatile在并发下依然会丢数据。经典例子是多个线程同时执行volatile int count的自增结果往往小于预期。再说synchronized。它既能保证原子性也能保证可见性。synchronized的底层依赖Monitor监视器锁在JVM中表现为对象头的Mark Word变化和锁升级过程。JDK 6之后锁有四种状态无锁、偏向锁、轻量级锁、重量级锁随着竞争加剧逐步升级。面试时能提到“锁升级”这三个字基本就能证明你没有停留在API层面。我见过一个很好的答题模板分享出来volatile适合做状态标记比如控制线程停止的running标志synchronized适合保护临界区比如多线程操作共享集合或累加器。要保证复合操作的原子性首选synchronized或Lockvolatile帮不上忙。另外如果面试官让你写一个线程安全的单例双重检查锁是最常见的答案。要注意instance字段必须用volatile修饰否则在极端情况下可能拿到未完全初始化的对象。这个考点几乎每年都会出现务必背到肌肉记忆。4.3 JVM内存区域与类加载基础面试必考点JVM题目看起来偏底层但基础面试里考得越来越多尤其是一线岗位。首当其冲的就是“JVM运行时数据区有哪些”建议按线程共享和线程隔离来分类记忆。内存区域是否线程共享主要作用程序计数器线程私有记录当前线程执行字节码的行号Java虚拟机栈线程私有存储栈帧保存局部变量表、操作数栈等信息本地方法栈线程私有本地方法调用所需Java堆线程共享对象实例和数组分配的主要区域方法区线程共享类信息、常量、静态变量等JDK 8后由Metaspace实现这里的高频追问是“JDK 8里方法区是不是没了”答案不是没了而是把原本的实现方式从永久代换成了元空间Metaspace并且字符串常量池也被移到了堆里。很多候选人一听到“永久代被移除”就回答“方法区没有了”这在概念上是不严谨的。方法区是JVM规范中的逻辑概念永久代和元空间是它的实现形式元空间用了本地内存不再受JVM堆大小限制。类加载机制里的双亲委派也是高频题。简单讲一个类加载器收到类加载请求时不会自己先去加载而是先委托给父加载器一直向上委托到启动类加载器如果父加载器无法完成加载子加载器才会自己尝试。这么做的核心目的是避免同名类被不同加载器重复加载也能避免核心API被篡改。JDK 9模块化之后加载器的名字有所调整但双亲委派的整体思想没有变化面试时按Bootstrap、Platform、Application这一套新版叫法说会更显得资料新。GC部分一般基础题只要求掌握“哪些区域需要GC”和“怎么判断对象可回收”。判断可回收最经典的是可达性分析从GCRoots出发遍历不到的对象就可以判定为可回收。注意“引用计数法”虽然简单但没法解决循环引用问题所以JVM用可达性分析。回答时顺带提一下四种引用类型和回收强度的区别就能覆盖大部分追问。5. 高频题速查表与两周备考执行方案5.1 高频题速查表这部分是我给身边人做面试突击时常用的速查表列了十个出现频率最高、也最适合在基础面中考查的题目每题给出一个答题切入点和加分点。可以把它当作最后的“背诵目录”使用。高频题核心答题切入点加分点Integer的比较包装类缓存机制自动装箱指出-128到127边界String创建了几个对象常量池与堆对象逻辑分常量池已存在/不存在两种场景ArrayList扩容机制默认容量10扩容后为1.5倍插入大量数据前主动ensureCapacityHashMap底层结构数组链表红黑树负载因子0.75解释树化阈值8的泊松分布背景重载与重写区别编译期与运行期的绑定差异能说出方法表分派机制接口与抽象类如何选择is-a用抽象类can-do用接口Java 8接口默认方法的影响受检异常与运行时异常编译期检查语义不同Spring事务默认回滚规则线程创建方式Runnable与Callable都能执行任务强调本质都是run方法双重检查锁单例volatile防止半初始化锁升级过程类加载双亲委派自底向上查找自顶向下委派为什么能避免核心类被篡改用这张表的方式特别适合冲刺阶段看到题目先在心里默答两分钟再看右侧的加分点自己能不能说出来。说不出来的就翻到前面对应的章节重新读一遍。5.2 两周过一轮的执行方案很多人拿到面试题汇总的第一反应是“从第一页背到最后一页”这个方法效率很低。我的经验是先搭框架再填细节。下面是适合大多数人的两周方案每天投入2到3小时即可。第一周做知识梳理每天一个主题第1天基本类型与包装类第2天String与不可变性第3天集合框架第4天面向对象第5天异常第6天泛型第7天把前六天的高频错题重新过一遍。这一阶段以“能画出现象和原理对应关系”为目标不用死记硬背。第二周做输出训练每天上午写一个专题的总结笔记下午做模拟问答。第8到第10天主攻并发第11到第12天主攻JVM第13天做综合速查表自测第14天进行两次完整的模拟面试。模拟面试时不要只做选择题最好找同伴互问或者对着录音把自己的答案讲一遍你会发现很多当时以为懂的内容说出来就卡壳。实操中还有个非常有效的方法把每个高频题都写成一问一答的形式然后模拟面试官从答案里挑一个词继续追问。比如你答了“HashMap树化阈值是8”面试官大概率会问“为什么是8”所以你笔记里就要在“8”的旁边用红笔补一行小字概率极低、防止哈希碰撞极端情况、并配合数组长度64判断。这样逐步把一个一个孤立知识点连成知识网络。5.3 面试过程中的三个实用细节第一答题要用体系化的结构别想到哪说到哪。不管是简单题还是难题都先给结论再解释原因最后补一个例子或经验。比如问“HashMap线程安全吗”标准结构就是“不安全并发修改会丢数据JDK 7可能出现环形链表JDK 8修复了环但并发写入问题仍在所以推荐用ConcurrentHashMap”这一串下去面试官能清晰感受到你脑子里是有结构框架的。第二遇到不会的题不要直接说“不知道”。可以把问题拆成自己知道的部分给出部分答案然后明说“这部分细节我没有深入实践过但我理解的思路是……”。我的经验是面试官更在意你面对未知知识时的推理过程而不是你是否背过所有答案。即使结论错了思路清晰也比沉默值钱得多。第三面试结束前通常有反问环节别问“公司加班多吗”这种问题可以问“团队目前用Java做的主要业务方向是什么”“线上JVM调优时遇到过哪些印象深刻的问题”这两个问题既能体现你的技术热情也能让你判断团队的技术深度和业务匹配度是一举两得的做法。最后说一点个人体会这套Java基础面试题汇总我每年都会整理更新3月这版又补了不少2026年新出现的提问角度。每次帮人准备面试我都会反复强调同一句话基础题不是背答案而是顺着答案把背后的原理讲清楚。比如HashMap的扩容哪怕你把数字背得再熟不理解为什么扩容要重新散列换了场景题一样答不好。我见过太多简历写得花团锦簇、一到基础知识就现原形的情况也见过不少平时默默无闻、但对每一个基础知识点都能讲出前因后果的朋友最后拿到理想offer。区别不在于背了多少题而在于有没有把每个知识点消化成自己的表达。建议你按照上面的两周方案过一轮把重心放在“能讲”“能推导”上再配合这张高频速查表做最后的查漏补缺。Java基础这一关只要肯花时间其实是所有面试环节里最容易稳拿分的部分。