try中return A,catch中return B,finally中return C,最终返回值是什么?
这个问题,其实是在考你对 finally 执行优先级 和 JVM 返回机制 的理解,属于看起来简单、一深究就露馅的经典题。
直接先说结果:
public static int test() {
try {
return 1; // A
} catch (Exception e) {
return 2; // B
} finally {
return 3; // C
}
}
// 最终返回值:3
👉 finally 里的 return C 会把前面 try 和 catch 里的 return 值直接“截胡”。
为什么是 3,而不是 1?¶
你脑袋里可以想象 JVM 在执行这段代码时的“微操”:
-
执行
try块里的代码,遇到了return 1—— 这时 JVM 不会立刻返回,而是先记下“我准备返回 1 了”,然后跑去执行finally块。 -
进到
finally里,结果碰上一个return 3—— 这相当于对 JVM 说:“刚才那个 1 不要了,现在就给我返回 3”。 -
于是
finally里的return直接覆盖了之前任何准备返回的值,方法最终返回 3。
🔹 哪怕 try 里没异常,走的也是这个流程,catch 根本不会触发,但 finally 横插一脚照抢不误。
再说个更容易混淆的变种¶
如果 finally 里没有 return,只是修改了变量的值呢?
public static int test() {
int x = 0;
try {
return x; // ① 准备返回 0
} finally {
x = 10; // ② 把 x 改成 10,但不 return
}
}
// 最终返回值:0
⚠️ 这里反而是很多人的翻车点。为什么还是 0?
因为 return x 在字节码层面,是先把 x 的值(基本类型)拷贝到一个临时槽位里,然后不管 finally 里怎么改 x 本身,最终返回的都是那个已经拷贝好的值。
如果 x 是引用类型,改的是对象内部状态,那才会影响返回值(因为引用拷贝的只是地址,指向的还是同一个对象)。
🔹 这题还藏着一个隐蔽考点:finally 到底什么时候不执行?
除了刚才说的 System.exit(0),还有:守护线程挂掉、JVM 崩溃、死循环卡住。其他情况下,即使 try/catch 里抛了异常,finally 也一定会跑完——这是它存在的意义。
你说这题像不像个“俄罗斯套娃”?你刚觉得自己理解了 return 被覆盖,它又用变量修改给你挖个新坑。面试能答到变量拷贝和引用类型这一层,基本就能和背八股的拉开差距了。如果再补一句“其实在字节码里,每个 return 前面都会被插入 finally 块的一个副本”,面试官大概就知道你是真翻过源码或看过字节码的人。