这三个关键字长得像,但作用和所属范畴完全不同,是Java面试的经典高频题。
一、核心区别表
| 关键字 | 核心作用 | 所属范畴 | 使用场景 | 关键特点 |
|---|---|---|---|---|
| final | 限制修改(不可变) | 修饰符 | 修饰变量/方法/类 | 编译期生效,手动编码控制不可变性 |
| finally | 保证代码块必执行 | 异常处理 | try-catch-finally 结构中 | 运行期生效,无论是否抛异常都执行 |
| finalize | 对象回收前的回调方法 | 垃圾回收(GC) | Object类的方法,可重写 | 运行期由GC调用,执行时机不可控 |
二、通俗解读
1. final:"最终的"------给代码加"不可修改锁"
通俗理解
final 是"修饰符",核心是禁止修改:
- 修饰变量:值/引用地址不可变;
- 修饰方法:子类不能重写;
- 修饰类:不能被继承。
代码示例
java
// 1. final修饰变量(基本类型值不可变,引用类型地址不可变)
final int MAX_NUM = 100;
// MAX_NUM = 200; // 编译报错:值不可改
final User user = new User("张三");
// user = new User("李四"); // 编译报错:地址不可改
user.setAge(25); // 合法:对象内部内容可改
// 2. final修饰方法(子类不能重写)
class Parent {
public final void coreMethod() {}
}
// class Child extends Parent {
// @Override
// public void coreMethod() {} // 编译报错:不能重写
// }
// 3. final修饰类(不能被继承)
final class FinalClass {}
// class SubClass extends FinalClass {} // 编译报错:不能继承
2. finally:"最终的"------异常处理的"兜底代码块"
通俗理解
finally 是"异常处理结构的一部分",核心是保证执行:
- 无论 try 块是否抛异常、catch 块是否捕获,finally 块一定执行;
- 唯一例外:执行
System.exit(0)强制终止JVM时,finally 不执行。
代码示例
java
public static void testFinally() {
FileInputStream fis = null;
try {
fis = new FileInputStream("test.txt");
// 模拟异常
int a = 1 / 0;
} catch (Exception e) {
System.out.println("捕获异常:" + e.getMessage());
} finally {
// 必执行:释放资源(如关闭流、数据库连接)
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("finally块执行:资源已释放");
}
}
// 调用结果:
// 捕获异常:/ by zero
// finally块执行:资源已释放
3. finalize:"最终化"------GC回收对象前的"遗言方法"
通俗理解
finalize 是 Object 类的保护方法,核心是:
- GC回收对象前会调用该方法,给对象最后一次释放资源的机会;
- 执行时机不可控(GC何时运行不确定),已被JDK9标记为过时(推荐用 try-with-resources 替代)。
代码示例
java
class Resource {
@Override
protected void finalize() throws Throwable {
super.finalize();
// GC回收前执行:释放资源(不推荐依赖)
System.out.println("对象即将被GC回收,执行finalize");
}
}
public static void testFinalize() {
// 创建对象,之后变为垃圾(无引用)
new Resource();
// 手动触发GC(仅建议,不保证立即执行)
System.gc();
}
// 可能的输出(执行时机不确定):
// 对象即将被GC回收,执行finalize
三、高频追问
追问1:finally 块一定会执行吗?
答:不一定!只有以下情况 finally 不会执行:
- 执行
System.exit(0)强制终止JVM; - 线程被杀死(如
Thread.stop()); - JVM崩溃(如硬件故障、强制关闭进程)。
其余情况(包括 try 块 return、catch 块抛异常),finally 都会执行。
追问2:try-catch-finally 中 return 的执行顺序?
答:finally 块在 return 之前执行(面试常考陷阱题):
java
public static int testReturn() {
try {
return 1;
} finally {
System.out.println("finally执行");
// 注意:finally中return会覆盖try的return值(不推荐这么写)
// return 2;
}
}
// 调用结果:
// finally执行
// 返回值:1
追问3:为什么不推荐使用 finalize?
答:
- 执行时机不可控:GC运行时间不确定,finalize 可能很久才执行,甚至不执行;
- 性能差:会延长对象回收周期,增加GC负担;
- 已过时:JDK9后标记为
@Deprecated,推荐用 try-with-resources、手动关闭资源等方式替代。
四、总结
请说说 final、finally、finalize 的区别?
答:
- final:是修饰符,核心作用是限制修改------修饰变量时值/地址不可变,修饰方法时不可被重写,修饰类时不可被继承,编译期生效;
- finally:是异常处理的一部分,用于 try-catch-finally 结构中,核心作用是保证代码块必执行(除非JVM强制终止),常用于释放资源(如关闭流、数据库连接),运行期生效;
- finalize :是 Object 类的保护方法,GC回收对象前会调用该方法,给对象最后一次释放资源的机会,但执行时机不可控,已被JDK9标记为过时,不推荐使用。
补充:三者仅拼写相似,核心作用和使用场景完全不同,final 关注"不可变",finally 关注"必执行",finalize 关注"GC回收前的回调"。
总结(关键点回顾)
- final:修饰符,管"不可变"(变量/方法/类);
- finally:异常处理,管"必执行"(释放资源);
- finalize:GC相关,管"回收前回调"(已过时,不推荐用);
- 核心区分:final 是编译期的"限制",finally 是运行期的"保证",finalize 是运行期的"不可控回调"。
简单记:final 改不了,finally 跑不掉,finalize 靠不住~