2026年的Java面试,给我最直观的感觉是:题目越来越“基础”,但问法越来越“穿透”。你背过String和HashMap能拿到60分,但能不能拿到offer,取决于你能不能把底层原理和项目里的真实场景串起来。这份Java面试题整理汇总,把我最近一年刷过的、帮读者复盘过的高频题目做了一次完整归档,包含答案思路、答题模板、避坑建议和实战话术。适合正在准备校招的应届生,也适合准备社招跳槽的初中级开发,甚至能帮刚转行的人快速建立Java面试的知识骨架。
我把这些题目按照“面试官到底想听什么”重新分组,不是简单罗列答案,而是告诉你每个问题背后在考察什么、怎么回答才能拿高分。面试这东西,知识点是死的,表达是活的,很多人栽就栽在知道答案却不会组织语言。
1. 2026年Java面试的考点地图
先看整体,再逐个击破。面试题再变,考点范围基本绕不开这几大块:Java基础与集合、并发编程、JVM、Spring家族、MySQL与Redis、分布式与微服务、算法与项目设计。我用一张我平时复习用的考点分布表来说明,按这个表去准备,命中率会高很多。
| 模块 | 高频考点 | 常见深度 |
|---|---|---|
| Java基础 | String、equals/hashCode、泛型、反射、面向对象 | 必须能手写场景,能说清"为什么" |
| 集合 | HashMap、ArrayList、ConcurrentHashMap | 底层结构、扩容、并发安全机制 |
| 并发 | synchronized、ReentrantLock、volatile、CAS、AQS、线程池 | 源码级追问概率很高 |
| JVM | 内存分区、GC算法、类加载、双亲委派、OOM排查 | 结合线上问题问 |
| Spring | IOC、AOP、Bean生命周期、Spring Boot自动配置 | 原理+源码入口 |
| 数据库 | MySQL索引、事务、MVCC、SQL优化、主从 | 给SQL让你分析,看执行计划 |
| Redis | 数据结构、持久化、缓存穿透/击穿/雪崩、分布式锁 | 结合项目场景问 |
| 分布式 | 分布式锁、分布式事务、接口幂等、消息队列 | 一般通过项目串着问 |
| 算法 | 排序、链表、二叉树、动态规划、TopK | 需要手写,约1~2道 |
这个表也是我给自己定的复习路线。基础模块先过一轮,然后并发和JVM花三到四天重点啃,Spring和数据库同步过,分布式和系统设计放到最后,靠项目经历来带动。你会发现,真正难的并不是单个题目,而是题目之间的连线。比如synchronized表面在考锁,实际在考对象头、内存屏障、锁膨胀、线程状态切换;Redis分布式锁表面在考setnx,实际在考原子性、锁续期、主从切换、性能取舍。面试官的水平差异也体现在这里,所以准备答案的时候,一定要按“结论+原理+场景”三层结构来准备。
2. 高频基础题拆解:String、HashMap、面向对象
这一节先把基础模块的高频题逐个拆开。基础题虽然看着简单,但恰恰是最容易翻车的,因为面试官可以通过追问把你“背过的答案”和“真正理解的答案”区分开。
2.1 String为什么用final修饰?StringBuilder和StringBuffer怎么选?
这道题几乎必考。标准答案要覆盖三个层面:不可变安全性、常量池复用、线程安全。
第一,String类用final修饰,内部char数组(JDK9以后是byte数组)也被final修饰,所有修改方法都返回新对象,所以String对象创建后内容不可变。不可变带来的好处是安全:可以作为HashMap的key,hashCode只计算一次缓存住;可以作为网络传输、数据库连接参数,不会被意外篡改;多线程环境下不需要额外加锁,天然线程安全。
第二,字符串常量池的存在依赖不可变性。String a = "java"; String b = "java";这两个引用指向常量池中同一个对象。如果String可变,那改a就会影响b,所以不可变才能实现共享。
第三,StringBuilder和StringBuffer的区别就是多了一个synchronized锁。StringBuffer的每个公开方法都加了同步,所以线程安全但性能略低;StringBuilder不加锁,单线程下性能更好。实际项目里,如果不是多线程共享同一个可变字符串,直接用StringBuilder。
面试官如果追问“字符串拼接底层是怎么做的”,你要说出:在JDK8中,+拼接字符串底层会转换成StringBuilder的append操作,但如果拼接发生在循环体内,编译器可能会重复创建StringBuilder,所以循环内大量拼接字符串时最好手动创建StringBuilder。
2.2 HashMap的底层原理和扩容机制
HashMap是Java基础面试的“题眼”,几乎没有人能跳过。高频考法主要围绕这几个点:底层结构、hash函数、put流程、扩容条件、JDK7和JDK8的区别。
底层结构是数组+链表+红黑树。JDK8中,当链表长度超过8并且数组长度大于等于64时,链表会转为红黑树;如果数组长度没到64,即使链表很长也会先扩容。这里“数组长度大于等于64”这个条件很多答案会漏掉,但面试官最喜欢在细节上卡人。
hash函数不是直接用key.hashCode,而是先让高位参与运算:(h = key.hashCode()) ^ (h >>> 16),目的是让哈希值的高位也能扰动低位,降低哈希冲突概率。定位数组下标时用(n - 1) & hash,前提是容量n是2的幂,这样可以用位运算替代取模,性能更好。
put流程要能说完整:先对key做hash扰动,然后定位数组下标;如果数组为空,先触发resize扩容;然后判断该位置是否有节点,如果没有就直接放进去;如果有就判断key是否相同,相同则覆盖value;否则判断节点是不是红黑树节点,是则走树插入,否则遍历链表,如果链表长度达到8且数组长度大于等于64就转红黑树。最后检查size是否超过阈值DEFAULT_LOAD_FACTOR * capacity,超过就扩容。
扩容机制:默认容量16,负载因子0.75,即元素个数超过12时扩容为原来的两倍。为什么负载因子是0.75?这是空间和时间的折中。负载因子太大(比如1),空间利用率高但哈希冲突和查询成本高;太小(比如0.5),查询快但浪费空间。扩容时JDK8做了优化,不需要重新计算每个元素的hash,而是通过判断元素hash值对应原容量highestBit的那一位是0还是1,来决定留在原位置还是移动到“原位置+oldCap”。
JDK7和JDK8的区别也常考:JDK7用头插法,JDK8用尾插法;JDK7数组是Entry,JDK8是Node;JDK8引入红黑树;JDK7扩容可能产生死循环,JDK8已经修复。
2.3 equals和hashCode为什么必须一起重写?
如果HashMap、HashSet、HashTable用了某个对象做key,hashCode决定对象被分到哪个桶,equals决定桶里哪个节点是你找的目标。重写equals不重写hashCode,会导致两个逻辑上相等的对象hashCode不同,HashMap把它们放到不同桶里,get的时候只能得到同一个桶里的结果,永远找不到你放进去的那个key。经典说法是:把hashCode比作“楼层”,equals比作“房间号”。两个对象要被视为相等,必须既在同一层,又在同一个房间。
重写规则:equals相等则hashCode必须相等;hashCode相等equals不一定相等,因为存在哈希冲突。所以在自定义实体类时,如果业务上需要按id或者业务字段做比较,一定要同时重写这两个方法。开发中能用Lombok的@EqualsAndHashCode,但我建议你还是手动写一遍,理解内部逻辑,面试时也能说得更清楚。
2.4 面向对象:重载和重写怎么区分?
重载发生在同一个类中,方法名相同,参数列表不同,与返回类型无关;重写发生在父子类之间,方法签名(方法名+参数列表)相同,子类可以改变访问修饰符但不能比父类更严格。重写的方法不能抛出比父类更宽泛的编译期异常。
面试官通常还会追问设计原则。常见的SOLID原则要会简述:单一职责、开闭原则、里氏替换、接口隔离、依赖倒置。尤其是开闭原则,在Spring里体现得非常明显:Spring的IOC通过配置文件或注解创建对象,加新功能不用改旧代码,而是扩展新的Bean;AOP也一样,通过切面加日志、权限,不改核心业务代码。
3. 并发与JVM:面试中的硬骨头
并发和JVM是Java面试的分水岭。我见过很多工作经验三年以上的候选人,项目做得不错,但一问到synchronized原理、线程池参数、G1回收过程就卡壳。不是他们不会,而是平时工作里没有形成系统性理解。这里挑了五个最高频的问题。
3.1 synchronized是重量级锁吗?
回答这个题,要说出锁的演变。JDK6以后,JVM对synchronized做了大量优化,引入了偏向锁、轻量级锁、重量级锁三种状态,锁只能升级不能降级,所以不能说它一直是重量级锁。偏向锁:无竞争时,一个线程多次获取同一把锁,会在对象头里记录线程ID,后续该线程再进入不需要CAS;轻量级锁:另一个线程来竞争时,通过CAS尝试在对象头中替换锁记录,如果成功则持有轻量级锁,如果失败就膨胀为重量级锁;重量级锁:依赖操作系统mutex实现,阻塞唤醒涉及用户态和内核态切换,成本高。
还要能说明锁大概的作用对象:普通同步方法锁的是当前实例对象,静态同步方法锁的是Class对象,同步代码块锁的是括号里的对象。提到对象头里的Mark Word,存储了hashCode、分代年龄、锁标志位等信息。
3.2 volatile和synchronized区别在哪?
volatile解决两个问题:可见性和有序性。它不解决原子性。线程修改变量后立即刷回主内存,读变量时从主内存重新读,这是可见性。编译器不会对volatile变量相关的指令做重排序,这是有序性。经典的单例双重检查锁为什么要加volatile?因为instance = new Singleton()不是原子操作,经历分配内存、初始化对象、把引用赋值给变量三步,CPU和编译器可能重排序,导致另一个线程拿到一个未初始化完成的对象。加上volatile可以禁止指令重排,保证先完成初始化再发布引用。
synchronized解决原子性、可见性、有序性三个问题,但代价是阻塞。所以在高频读低频写的场景优先用volatile,在需要原子操作的互斥场景用synchronized或Lock。
3.3 线程池的核心参数和工作流程
线程池这块我强烈建议直接背下ThreadPoolExecutor的7个参数:corePoolSize核心线程数、maximumPoolSize最大线程数、keepAliveTime非核心线程存活时间、unit时间单位、workQueue阻塞队列、threadFactory线程工厂、handler拒绝策略。记住一个公式:提交任务时,如果线程数小于核心线程数,就创建线程;如果大于等于核心线程数,先把任务放队列;队列满并且线程数小于最大线程数,创建非核心线程;队列满且线程数达到最大值,执行拒绝策略。
拒绝策略有四种:AbortPolicy直接抛异常,默认;CallerRunsPolicy由调用线程执行任务;DiscardPolicy静默丢弃;DiscardOldestPolicy丢弃最老任务。我实际项目里最常用的是CallerRunsPolicy,因为它能保证任务不丢,而且通过让调用方自己执行来形成天然背压。
面试还会追问“核心线程数怎么设置”。CPU密集型任务推荐N+1,N是CPU核数;IO密集型任务推荐2N,因为IO等待时CPU可以切换执行其他线程。老司机补充一句:现在云服务器核数很容易查,但还要考虑业务是否有数据库连接、第三方调用,如果混布,一定要压测调优,公式只能作为起点。我用WriteExecutor举例,IO密集型场景设置2N甚至2N+1,效果明显。
3.4 AQS是什么?ReentrantLock和synchronized的区别
AQS即AbstractQueuedSynchronizer,是JUC同步器的基础框架。核心是state状态变量 + CLH变体队列。每次加锁就通过CAS修改state,抢不到锁的线程被封装成Node节点放入队尾并阻塞,释放锁时把队首节点唤醒。ReentrantLock、Semaphore、CountDownLatch、ReadWriteLock都基于AQS实现。
ReentrantLock和synchronized的区别要能说清:synchronized是关键字,由JVM实现;ReentrantLock是API,由Java类实现。synchronized可以自动释放锁,ReentrantLock需要手动lock和unlock,必须在finally里释放。ReentrantLock支持可中断获取锁lockInterruptibly()、支持公平锁/非公平锁、支持多个Condition实现精确唤醒。需要公平场景、需要中断响应、需要超时获取锁时,优先用ReentrantLock,否则用更简单的synchronized。
3.5 JVM内存分区和GC流程
JVM运行时数据区:程序计数器、虚拟机栈、本地方法栈、方法区/元空间、堆。其中栈是线程私有的,堆是线程共享的,也是GC最关注的地方。JDK8以后方法区改名为元空间,使用本地内存,不再容易OOM,但元空间无限增长时也会被系统内存拖死。
GC算法要会概括:标记-清除有碎片但快,标记-整理没有碎片但需要移动对象,复制算法适合存活率低的新生代。大多数JVM新生代用复制算法,老年代用标记-整理或标记-清除。现代垃圾收集器重点了解G1:它是区域化分代收集,把堆分成大小相等的Region,维护一个优先列表,每次都优先回收价值最大的Region。关注四个概念:Region、Remember Set(跨Region引用记录)、Mixed GC、可预测停顿。ZGC如果时间充裕也值得了解,核心是染色指针和读屏障,停顿时间控制在十毫秒级别。
OOM排查是最贴合实际工作的考点。要能说出步骤:先通过jps找到进程,jmap -heap查看堆情况,如果内存紧张就jmap -dump:format=b,file=heap.hprof导出堆快照,用MAT分析。如果是CPU飙高,用top -Hp找线程,jstack看线程栈,很多情况是死循环、GC线程、等待锁。这里我提醒下,很多公司线上环境不让随便装工具,最好提前知道容器能不能用jmap,如果不能,可以在启动参数里加-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/path,让JVM在OOM时自动留“案发现场”。
3.6 类加载和双亲委派
类加载过程:加载、验证、准备、解析、初始化。双亲委派是说,一个类加载器收到类加载请求时,不会自己加载,而是先让父加载器加载,父加载器加载不了才轮到子加载器。这样可以防止核心类库被篡改,比如你写一个java.lang.String,AppClassLoader会把它抛给BootstrapClassLoader,Bootstrap发现已经有rt.jar里的String,就直接返回核心类,你自定义的类永远不会被加载。面试经常会问“怎么打破双亲委派”,Tomcat和JDBC都打破了,但如果你没看过源码,我建议诚实说“了解Spring使用SPI加载Driver,但没有自己实现过”,不要硬编。项目场景里,热部署插件、Dubbo这类框架才会实际涉及。
4. 框架与存储:Spring Boot、MySQL、Redis高频问答
这一部分直接决定你能不能在面试里体现出“做过项目”的水平。框架题不能只背注解,要让面试官觉得你真的用它解决过问题。
4.1 Spring IOC和AOP的核心理解
面试官问你IOC是什么,不要只说“控制反转”,要说:传统的对象创建由程序自己new,控制权在程序员;Spring把对象创建、依赖注入、生命周期的管理交给容器,所以叫控制反转。依赖注入是IOC的一种实现方式,通过构造器、setter、字段注入实现Bean之间的解耦。举一个例子:订单服务要发通知,以前直接new EmailService,现在定义一个MessageService接口,用@Autowired注入,后续换成短信服务时不需要改订单服务代码,只改配置或实现类。
AOP关键是理解动态代理:Spring默认对接口使用JDK动态代理,对类使用CGLIB代理。JDK动态代理必须实现接口,调用链是InvocationHandler;CGLIB通过继承目标类生成字节码子类来重写方法。日常用的@Transactional原理就是AOP,它通过代理对象拦截方法,在方法前开启事务,方法后提交/回滚。
被追问“Spring容器中Bean的生命周期”时,要按顺序说:创建对象(实例化)、属性填充、BeanNameAware等Aware接口回调、BeanPostProcessor前置处理、初始化方法(InitializingBean或@PostConstruct)、BeanPostProcessor后置处理、使用Bean,销毁时执行DisposableBean或@PreDestroy。记住两三个关键节点即可:BeanPostProcessor是AOP动态代理植入的最佳时机,所以Spring事务为什么能生效,是因为代理在初始化阶段就生成了。
4.2 Spring Boot自动配置的原理
Spring Boot最核心的一句话:基于“约定优于配置”的自动配置。入口是@SpringBootApplication,它由@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan组成。@EnableAutoConfiguration会通过AutoConfigurationImportSelector读取META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件里的配置类(以前是spring.factories),然后按条件注解@ConditionalOnClass、@ConditionalOnMissingBean去判断是否生效。比如我们引入了spring-boot-starter-data-redis,RedisAutoConfiguration才会生效,并且如果用户没有自定义RedisTemplate才创建默认的。
实际面试高频题是“为什么Spring Boot的配置文件改个属性就生效”,要能提到@ConfigurationProperties绑定配置到对应属性类,再被AutoConfiguration里的Bean使用。准备这个题时,建议去读一下RedisAutoConfiguration和DataSourceAutoConfiguration源码,读两遍你就能理解整个自动配置的套路。
4.3 MySQL索引为什么用B+树?
答案是:B+树在做范围查询时性能好,叶子节点之间用链表串联,而且非叶子节点只存索引不存数据,一页能存更多key,树高更矮,磁盘IO次数更少。HashMap不能范围查询,有序数组适合范围查询但插入删除要移动大量数据,普通二叉树在极端情况下退化成链表导致树太高。这个题其实是数据结构选型题,落地到MySQL,InnoDB的聚簇索引叶子节点存整行数据,二级索引叶子节点存主键值,所以如果只用二级索引查询字段,就会发生回表。问“怎么优化慢查询”,第一反应是explain看type、key、rows、Extra,特别关注有没有Using filesort和Using temporary。
我再补一个很容易被忽略的点:联合索引的最左前缀原则。索引顺序(a, b, c),查询时如果跳过a只用b和c,索引就用不上。所以建联合索引时,要把区分度高的字段放前面,同时考虑查询条件组合。比如订单表常用user_id和create_time查询,那(user_id, create_time)比(create_time, user_id)更合适。
4.4 MySQL事务隔离级别和MVCC
事务四大特性ACID要记牢:原子性、一致性、隔离性、持久性。Undo Log保证原子性(回滚),Redo Log保证持久性(崩溃恢复),锁和MVCC保证隔离性和一致性。隔离级别从低到高:读未提交、读已提交、可重复读、串行化。MySQL默认是可重复读。
高频追问“MVCC怎么做快照读的”:MVCC通过隐藏字段(row_id、事务ID、回滚指针)和Undo Log构造版本链,再配合ReadView判断哪个版本对当前事务可见。InnoDB在可重复读级别下,事务第一次执行select时创建ReadView,之后一直用同一个ReadView,因此也叫“一致性快照读”。当前读(select for update、update、delete)需要走最新版本并加锁,所以可能仍然产生幻读。next-key lock(记录锁+间隙锁)可以解决当前读的幻读。面试能答到这个程度,已经超过大多数候选人。
4.5 Redis缓存穿透、击穿、雪崩和分布式锁
这三个问题成为经典不是偶然,因为它们代表了缓存层最常见的三类故障。穿透是查一个一定不存在的key,请求直接打到数据库,解决思路是缓存空值、布隆过滤器,加一个参数校验;击穿是某个热点key在过期瞬间有大量请求同时打到数据库,解决思路是互斥锁重建缓存、热点key逻辑过期、Redis里把key设置为不失效定期更新;雪崩是大量key同一时间过期或者Redis宕机,解决思路是过期时间加随机值、热点数据由后台统一更新、Redis高可用集群、多级缓存。
分布式锁最经典的Redis实现:用SET key value NX EX 5命令,返回OK说明抢到锁。这里要强调SET命令的NX和EX参数必须一起写,保证原子性。释放锁时不能直接del,要先判断value是不是自己的线程标识,防止误删别人的锁,而且这个“判断+删除”必须用Lua脚本保证原子性。锁的有效时间也是个坑,业务执行超过expire时间怎么办?Redisson提供了看门狗机制,每10秒自动续期,如果服务宕机锁到期自动释放。至于RedLock,不加评论,真实生产用Redisson或者引入ZooKeeper/etcd的更多,面试能说清Redis实现和续期逻辑就够了。
4.6 分布式事务和数据一致性
这个题现在越来越多。面试官问“怎么保证数据一致性”,你要先反问:是同步调用还是异步消息?是强一致还是最终一致?然后对应给方案。同步调用场景:本地事务 + 事务消息;本地消息表:业务表和消息表在同一个本地事务里写,然后生产消息,消费端保证幂等。最终一致常见方案:基于MQ,生产者发半消息给RocketMQ,执行本地事务,提交后消息才可见,消费者消费成功后写消息轨迹,失败重试,配合定时任务对账。
接口幂等也是高频:数据库唯一约束、Redis setnx、状态机字段、版本号。我做过的一个订单服务,支付回调处理时先查订单状态,根据订单状态更新,再用乐观锁version防并发。这里要记住一个原则:先给面试官一个“我会优先考虑强一致还是最终一致”的判断,再上细节,比直接背方案更能拿高分。
5. 实操准备:从背题到会答题
很多候选人知道所有答案,但面试表达出来就是“背书感”很强。这一节分享怎么把知识答案变成面试答案。
5.1 用三层结构组织答案
面试官问一个知识点时,先用一句话给结论,再用一两句话讲原理,最后结合项目说落地。比如问“Redis分布式锁你怎么用”,不要上来就念命令,你可以这样说:我通常用Redisson的RLock,因为它在setnx基础上解决了锁续期问题;它的加锁核心是Lua脚本,保证原子性;我们有个订单取消场景,一台服务节点可能同时处理同一个订单,为了避免重复调用第三方取消接口,我用订单号作为锁key,锁过期时间30秒,业务主流程控制在5秒内,万一异常提前释放也不会误删别人锁。这句话里,结论、原理、场景都有了。
平时复习时,对每个高频题都做一次“如果面试官只让我讲三分钟,我怎么讲”,提前组织好话术。尤其要注意,不要一上来就列一堆源码细节,面试官想听的是“你的思考层级”和“你的表达能力”,如果一开始就把底层铺开,反而会让对方觉得你没有结构化思维。
5.2 项目经历怎么讲才不打折
Java面试几乎必然有项目介绍环节。我推荐用STAR法则讲:背景(Situation)、任务(Task)、行动(Action)、结果(Result)。讲的时候要突出“遇到的问题”和“你的思考”。比如简历写了“负责订单模块开发”,面试官大概率问:“订单状态流转你怎么设计的?如果并发重复提交怎么处理?下单和库存扣减怎么保证一致性?”如果没有准备,临场发挥容易说成流水账。
我建议提前为简历里每个项目写三张卡片:一是项目整体架构图(用什么框架、几个服务、怎么通信);二是你负责模块的详细流程(核心表结构、关键接口、调用链路);三是两个可深谈的亮点,比如性能优化、并发问题、缓存一致性,每个亮点对应三道可能追问的八股题。比如你做过一个报表导出,前期Excel导出慢,后来改成异步任务+线程池并行导出,这样“线程池参数怎么设置”“为什么用CompletableFuture”“如何分页查询避免OOM”这些题就全都能串起来。
5.3 算法题短期突破
算法题现在基本是必考环节,但难度不像LeetCode hard那样吓人。高频类型集中在:数组、链表、二分、二叉树、栈队列、字符串、动态规划入门、TopK、排序变种。复习策略是“分类刷题+模板总结”:链表题统一掌握dummy节点+双指针思路;二叉树题掌握递归三件套(终止条件、递归参数、返回值含义);TopK题会用大顶堆/小顶堆和快速选择法。我常说在线编译环境不熟,所以笔试前一定要去牛客或者LeetCode把输入输出练熟。手写代码时先写清楚思路,再动笔,至少要保证每道题时间复杂度说清楚。
6. 简历和面试中的常见问题排查
最后这部分是我在帮读者做模拟面试时遇到的高频问题,直接上清单,像排查故障一样逐个对照。
6.1 背过的题一到面试就忘,怎么办?
这不是记忆力问题,是知识没有组织。我给的药方是“画知识树+费曼输出”。每学一个模块,都问自己:“如果让我现在就讲清楚HashMap的put流程,我能讲吗?”先用10分钟在纸上默写流程图,找出卡壳的地方再回看笔记。也可以用录音笔或手机把自己讲的内容录下来,回放时会发现很多细节漏了。另一个小技巧是做“关键词卡片”,每个题只写三个引导词。比如线程池卡片写“核心参数、队列满、拒绝策略”,回忆时看到这三个词,就能把整个流程展开。
6.2 简历写的技术栈太多,面试官问得很散怎么办?
不要什么都会一点就全写。简历写技术栈的原则是“能接受追问的才写”。你写了Vue,就要能回答Vue生命周期;写了Docker,就要能说清镜像和容器的区别、常用命令、构建流程;写了Kafka,就要能说清分区、消费组、消息丢失和重复消费。建议上线前用“三个为什么”自查:这个技术为什么用?项目里用在哪?如果它出问题了怎么排查?任何一个“为什么”答不上来,就不写或者先补课。项目里最常用的技术栈写3~5个足够。
6.3 手写SQL不熟,怎么快速补救?
SQL是Java面试经常交手的环节。至少要掌握:建表和索引语法、常用聚合函数、join、子查询、行转列(case when)、窗口函数。窗口函数是这两年的加分项,常用的有row_number、rank、sum() over(partition by)。先自己建两张表,比如学生表和成绩表,练习“每科成绩排名”“连续登录天数”这些典型场景,比死背规范要有效。真的不会时,先跟面试官确认表结构,再考虑最优写法,不要闷头写。
6.4 面试聊崩了,怎么救?
面试聊崩通常是两种情况:一是过度紧张导致没听懂问题;二是想强行套背过的答案。我建议在遇到一个没准备的题时,先复述一遍:“您是问在分布式事务里,本地消息表模式怎么保证最终一致,对吗?”这样既能给自己争取思考时间,也避免答非所问。如果确实不会,可以诚实说:“这块我只了解概念,还没有在生产环境实践过,我理解大概是……回去我会补一下。”大多数面试官能接受坦诚,最反感的是编造。
准备Java面试从来不是背完一份题就万事大吉,重点是把每条答案变成自己可以随时调用的经验。我个人在带人准备面试时,最后一周会让他们把所有高频题按“如果我是面试官,我会怎么继续追问”过两遍,这个方法效果很明显。你背到自己能提问、能回答,才是真的掌握了。到面试现场,再遇到“HashMap扩容为什么是2倍”、“Redis锁续期怎么实现”、“MySQL为什么用B+树”这类问题时,你自然会有底气慢慢讲。希望这份2026年Java面试题汇总能帮你把零散的知识串成体系,少踩几个我踩过的坑。