你自以为熟悉的Java一问就倒前几天帮朋友模拟面试他简历上写着“精通Java”三年经验。我随口问了一句“HashMap的put方法当发生哈希碰撞时链表什么时候转红黑树”他愣了三秒开始磕磕绊绊地背源码行数。我又问“那红黑树在什么情况下会退化回链表”他直接沉默了。这不是个例。Java面试真正的拦路虎从来不是语法糖或者API用法而是那些你自以为“会用就行”的底层原理。在一个技术团队里真正决定代码质量的往往是面试官能从这些核心问题里测出的思维深度。今天我就以一个面试官的身份把那些反复出现、一针见血的问题清单公开并告诉你为什么这些问题能瞬间筛掉80%的候选人。基础篇String到底有多“不可变”很多人张口就来“String是不可变类。”那你问一句String s abc; s s d;发生了什么他可能会说“生成了新对象”但再问“原始字符串对象被回收了吗”就答不上来了。真正的核心问题清单第一题String的不可变性究竟保证了什么答案远不止“不可修改”——它保证了字符串常量池的线程安全保证了哈希码的缓存效率甚至保证了类加载机制中的安全校验。如果你答不出“String的不可变性是JVM安全模型的基础之一”说明你还没理解这门语言的底层设计哲学。再问StringBuilder和StringBuffer的区别面试官真正想听的不是“前者线程不安全后者线程安全”而是为什么单线程下StringBuilder更快关键点在于StringBuffer所有public方法都加了synchronized而同步带来的锁竞争开销在单线程下是纯浪费。但更深入一层JVM对StringBuffer做了锁消除优化吗这就涉及逃逸分析了。集合篇HashMap是你心里的一根刺几乎每个面试官都会问HashMap但很少有人能扛住连环追问。核心问题清单第二题HashMap在JDK 1.7和1.8中有什么区别99%的候选人会答“1.7是数组链表1.8是数组链表红黑树。”然后就没有然后了。面试官想听的是为什么引入红黑树阈值为什么是8链表查询时间复杂度O(n)红黑树O(log n)但红黑树节点更大占用内存更多。当链表长度小于6时红黑树的查找优势已经不足以抵消它的空间和旋转开销所以阈值设计为8转为树6退化为链表。中间的7是缓冲防止频繁转换。第三题HashMap的扩容机制为什么是2的幂次你可能会说“位运算取模效率高”——对了一半。更关键的原因是扩容时元素在新数组中的索引要么在原位置要么在原位置旧容量。这个特性来自于hash (newCap - 1)的计算方式而旧索引是hash (oldCap - 1)。如果扩容为2倍那么hash值多出的那一位决定了位置偏移。这种设计使得扩容时不需要重新计算每个元素的哈希只需要看新增的那一位是0还是1极大提升了效率。还有第四题ConcurrentHashMap在JDK 1.7和1.8中分别怎么保证并发安全 1.7用Segment分段锁1.8用CASsynchronized。为什么1.8放弃了分段锁因为分段锁的粒度太粗最多支持16个并发Segment数量固定而CASsynchronized的粒度精细到每个桶并发度更高。更重要的是synchronized在JDK 1.6之后经过大量优化偏向锁、轻量级锁性能已经不输ReentrantLock。并发篇volatile不是玄学第五题volatile能保证原子性吗这是经典的陷阱题。很多人说“能”然后被反问“i用volatile修饰是否线程安全”就露馅了。volatile只保证可见性和有序性不保证原子性。i是读-改-写三步操作volatile无法阻止指令交错。但有一种情况例外对volatile变量的单次读写操作比如boolean标志位是原子性的因为64位基本类型long/double在32位JVM上可能分两次写入volatile保证了其原子性。第六题synchronized和ReentrantLock的区别面试官真正想听什么千万别只背“前者是关键字后者是类”。核心区别在于synchronized是非公平锁ReentrantLock默认非公平但可以设置为公平锁。但更本质的是synchronized是JVM层面的锁依赖monitor对象而ReentrantLock是API层面的锁内部通过AQS实现。后者提供了超时、可中断、多条件变量等特性。还有一个冷门但关键的点synchronized在JDK 1.6之后引入了偏向锁、轻量级锁、重量级锁的升级过程而ReentrantLock的lock()方法直接CAS抢锁没有偏向机制。第七题ThreadLocal的内存泄漏问题你处理过吗很多人知道ThreadLocalMap的key是弱引用但弱引用只针对keyvalue是强引用。如果线程一直存活比如线程池里的线程而ThreadLocal对象被垃圾回收了那么key变成nullvalue却永远不会被回收。解决方案是在使用后手动调用remove()。但更深刻的思考是为什么设计成弱引用因为如果不设计成弱引用即使程序员忘记remove只要ThreadLocal对象还在比如静态变量key和value就都无法回收造成更严重的内存泄漏。弱引用至少提供了一层保障当ThreadLocal被GC后key自动变null下次get/set时可以清理。JVM篇垃圾回收不只是八股第八题CMS和G1的区别别再背“低延迟、吞吐量优先”了。问为什么CMS会引发“Concurrent Mode Failure”因为CMS的并发清理阶段是和工作线程并发执行的如果此时老年代空间不足CMS不得不退化为Serial Old进行Full GC。而G1通过设置预期的停顿时间将堆划分为多个Region每次只回收一部分Region避免全堆扫描。但G1也有缺点当对象分配速度极快时G1的混合回收可能追不上分配速度导致Full GC。第九题你经历过哪些OOM怎么分析的常见的OOM有堆内存溢出、栈内存溢出、元空间溢出、直接内存溢出。面试官想听的是你如何定位用jmap dump堆用MAT分析GC Roots引用链或者用jstat看GC情况用jstack看线程栈。真正加分的是你能否区分“内存泄漏”和“内存溢出”泄漏是对象无用但被引用无法回收溢出是对象确实需要但内存不够。泄漏的典型场景是ThreadLocal不remove、静态集合类不断添加元素。第十题类加载过程是“加载-验证-准备-解析-初始化”的哪一步大多数人会背这个顺序但问“什么时候会触发一个类的初始化” 只有四个主动使用场景new、反射、访问静态变量非final、子类初始化触发父类。被动引用不会触发初始化比如通过子类引用父类的静态字段、定义数组引用等。还有一个更深的点接口的初始化规则不同只有使用接口中的非常量字段时才会触发。Spring篇依赖注入不只是注解第十一题Spring Bean的作用域有哪些这个太基础但面试官真正想问的是request和session作用域在web环境下怎么生效的底层原理是什么答通过代理模式Spring为request和session作用的Bean创建代理对象在每次调用时从当前请求/会话上下文中获取实际实例。核心技术是ObjectFactory的延迟查找。第十二题Autowird和Resource的区别很多人说“前者按类型后者按名称”。但Resource是JSR-250标准Autowired是Spring专有。更关键的是Autowired可以用在构造函数上实现构造器注入这是推荐的方式因为构造器注入可以保证依赖不可变、不需要setter、且更容易检测循环依赖。循环依赖问题也是面试高频为什么构造器注入解决不了循环依赖因为构造器注入发生在Bean创建阶段此时实例还未完全初始化无法通过三级缓存singletonFactories提前暴露半成品对象。而setter注入可以因为Spring通过三级缓存EarlySingletonReference解决了循环依赖。第十三题Spring事务的传播行为你真的理解吗REQUIRED、REQUIRES_NEW、NESTED……别只背定义。面试官会问如果外层方法没有事务内层方法有REQUIRES_NEW会怎么样答案各自独立创建新事务。但更常见的坑是同一个类中方法A调用方法BB的Transactional会失效。因为Spring事务通过AOP代理实现方法A内部直接调用方法Bthis.B()走的是原生对象没有经过代理。解决方案是注入自身代理或使用AopContext.currentProxy()。总结面试官到底在找什么这些核心问题清单每一个都不是为了考倒你而是为了检测你构建知识体系的能力。一个只会背八股的人当被追问“为什么”的时候会漏洞百出。而一个真正理解底层的人能从一处细节推演出整个设计逻辑。当你下次面试时如果面试官问“说说你对HashMap的理解”不要从数组链表开始背而是直击灵魂地回答“我认为HashMap最核心的设计是哈希算法与扩容机制之间的协同它利用2的幂次特性避免了rehash用红黑树来解决哈希碰撞严重时的退化问题。”——这才是面试官想听到的答案。最后送你一句我作为面试官最想说的话别把Java当工具把它当一门可以无限深入的艺术。每一次底层原理的穷追都在帮你从“API调用者”进阶为“架构设计者”。希望这份清单能成为你下一场面试的转折点。