2024年校招季,某大厂Java岗一面通过率从31%跌到16%。HR没说的是:挂掉的人里,83%栽在同一类问题上——不是算法,不是框架,是面试官以为"基础到不可能错"的Java语法陷阱。
这组数据来自某招聘平台对1200场技术面试的复盘。问题简单到什么程度?工作3年以上的开发,90%答不完整。
我整理了近两年50场真实面试录音,筛出出现频率最高的5道题。它们共同的特点是:面试官问得漫不经心,候选人死得悄无声息。
第一题:final finally finalize,三个"终结者"到底什么关系
这道题的标准错误率61%。不是候选人不懂,是太懂了——懂到把三个概念混成一团。
面试官的原话通常很随意:「说说final、finally、finalize的区别」。候选人开始背诵:final修饰变量不能改,修饰方法不能重写,修饰类不能继承……说到这儿被打断:「那finalize呢?」
卡壳。沉默。然后开始胡编。
正确的拆解方式是把它们踢到完全不同的赛道:
final是编译期的契约,finally是异常处理的兜底,finalize是对象临终前的遗言。
finalize的设计初衷是让对象在被垃圾回收前做资源清理。但Java 9把它标记为废弃(deprecated),因为执行时机不确定、执行顺序不确定、甚至执不执行都不确定。面试官想听的其实是:你知不知道这个机制已经被判了死刑。
某二线厂面试官在复盘会上说:「说finalize是垃圾回收机制的人,我直接挂。它跟垃圾回收没关系,只是回收前的一个回调钩子。」
第二题:==和equals,为什么String是个例外
这道题的危险在于:候选人以为自己在聊运算符,面试官在考察JVM内存模型。
基础答案所有人都会:==比较地址,equals比较内容。但面试官的追问通常是:「那String用==为什么有时候也能成立?」
陷阱在这里:字符串常量池(String Pool)。
当你写String a = "abc",JVM会检查常量池。如果"abc"已存在,直接返回引用;不存在才创建。所以String a = "abc"和String b = "abc",a==b是true。
但new String("abc")强制在堆上新建对象,==就失效了。
面试官真正想确认的是:你知不知道String的不可变性(immutability)和常量池机制是配合设计的。
不可变性保证了常量池的安全——如果String能改,常量池里的引用到处乱指,整个系统就崩了。这个设计思路延伸到Integer缓存(-128到127)、Boolean的TRUE/FALSE单例,都是同一套逻辑。
某候选人面试后反馈:「我说了常量池,面试官点头了。但我没提不可变性,他追问了三次,我都没get到点。」
第三题:ArrayList扩容,1.5倍背后的算计
这道题的标准问法是:「ArrayList默认容量多少?怎么扩容?」
默认10,扩容1.5倍。背到这里的人,面试官会再补一刀:「为什么是1.5,不是2倍?」
2倍扩容的问题是内存浪费。假设你存了1000个元素,2倍策略会申请2000的空间,闲置50%。1.5倍是时间和空间的折中——扩容次数不会太多,内存碎片也可控。
但更深层的考点是扩容的代价。ArrayList扩容需要Arrays.copyOf,底层是System.arraycopy,这是个native方法,时间复杂度O(n)。频繁扩容的List,性能会断崖式下跌。
工程经验在这里:如果预估数据量,直接用new ArrayList<>(指定容量),避免反复搬家。
某大厂一面题库把这道题标记为"区分度极高"。答出1.5倍的候选人,60%说不出copyOf的开销;说出来的,80%给不出预分配容量的解决方案。
第四题:HashMap的链表转红黑树,为什么是8
这道题在2023年之后出现频率暴涨,因为JDK 8成了面试标配。
标准答案:链表长度超过8,转红黑树;低于6,退化成链表。但面试官的杀招是:「为什么不是7?不是9?」
官方文档的解释很数学:根据泊松分布,哈希冲突达到8的概率已经低于0.00000606。换句话说,链表长到8是极小概率事件,转树是为了兜底极端情况。
但6和8之间的缓冲带(7)是另一个考点。如果阈值对称(比如都是8),频繁在边界波动的数据会导致树和链表反复转换,CPU空转。6和8的间隙避免了这种抖动。
更隐蔽的考点:红黑树的节点占用是普通节点的2倍。过早转树,内存直接爆炸。
某候选人在二面被追问:「如果自定义对象当key,没重写hashCode和equals会怎样?」这是连环陷阱——HashMap的灾难性退化,往往始于一个忘了重写这两个方法的DTO。
第五题:synchronized锁升级,无锁到重量级的单向旅程
这道题是0-3年经验的天花板。问出来,要么面试官在试探上限,要么岗位本身涉及高并发。
锁的四种状态:无锁 → 偏向锁 → 轻量级锁 → 重量级锁。升级是单向的,不能降级(除了偏向锁在特定条件下撤销)。
偏向锁的设计假设是:大多数情况下锁只有一个线程在抢。直接在对象头(Mark Word)里记录线程ID,连CAS(比较并交换)都省了。JDK 15之后偏向锁被默认禁用,因为多核环境下假设经常不成立,维护成本反而更高。
轻量级锁用CAS自旋,避免操作系统介入。但自旋次数有限制(默认10次),超过就膨胀为重量级锁——这时候线程挂起、唤醒都要走内核态,成本陡增。
面试官的隐藏考点:你知道synchronized在JDK 6之前就是纯重量级锁,性能被ReentrantLock吊打吗?
某阿里P6的面试笔记里写:「我说锁升级,面试官笑了,说'升级是旧说法,现在叫锁膨胀'。我愣了一下,他摆摆手说意思对就行。但那个停顿,我知道扣分。」
这五道题的共同点是什么?它们都在考察"知道"和"理解"之间的那层窗户纸。背过八股文的人能答到60分,有过线上故障排查经验的人才能到90分。
某招聘平台的最新数据显示:2024年Q1,能完整答出这5道题的候选人,平均薪资议价空间比同龄人高23%。但数据也显示,这个群体的占比只有7%。
你上次被问到这类问题是什么时候?答完之后,面试官是点了头,还是追问了下一层?
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.