final、finally和finalize是Java语言中三个看似相似但用途迥异的关键概念,理解它们的区别是Java开发者必须掌握的基础知识,也是技术面试中的常见考点。
final 关键字
final 是一个修饰符关键字,用于声明类、方法或变量,表示它们具有“不可变性”。
-
final 类:该类不能被继承。
public final class FinalClass {
// 类内容
}
// public class SubClass extends FinalClass { // 编译错误,不能继承 final 类
// }
-
final 方法:该方法不能被子类重写(Override)。
public class BaseClass {
public final void display() {
System.out.println("This is a final method.");
}
}
public class DerivedClass extends BaseClass {
// public void display() { // 编译错误,不能重写 final 方法
// System.out.println("Trying to override.");
// }
}
-
final 变量:该变量一旦被初始化赋值,其值就不能再被修改。对于基本类型,值不变;对于引用类型,引用指向的对象地址不变(但对象内部状态可能改变)。
public class MyClass {
public static final int MY_CONSTANT = 10; // 常量
private final List<String> list = new ArrayList<>(); // 引用不可变,但list内容可增删
}
finally 代码块
finally 是与 try-catch 语句配合使用的代码块,用于放置必须执行的清理代码,无论是否发生异常,finally 块中的代码通常都会执行。
常见的应用场景包括关闭数据库连接、释放文件句柄、确保锁被解锁等。
try {
// 可能抛出异常的代码
} catch (Exception e) {
// 异常处理逻辑
} finally {
// 清理代码,无论是否发生异常都会执行
// 例如:conn.close();
}
可以使用 try-finally 或 try-catch-finally 结构。
注意:在几种极端情况下,finally 块可能不会被执行,在涉及并发与资源管理的场景中需要特别注意:
- JVM 非正常退出:程序调用
System.exit(int status) 强制终止虚拟机。
try {
System.out.println("Try block");
System.exit(0); // JVM退出,finally不执行
} finally {
System.out.println("Finally block"); // 不会打印
}
- 无限循环或死锁:
try 或 catch 块中的代码导致线程陷入无限循环或死锁,程序无法正常执行到 finally 块。
- 致命错误:
try 块中发生了 OutOfMemoryError(内存耗尽)等致命错误,导致JVM进程异常终止。
try {
List<byte[]> list = new ArrayList<>();
while (true) {
list.add(new byte[10 * 1024 * 1024]); // 持续消耗内存,最终OOM
}
} finally {
System.out.println("Finally block"); // OOM后很可能不会执行
}
finalize 方法
finalize() 是 Object 类中定义的一个受保护方法。设计初衷是让对象在被垃圾回收器回收之前,有机会执行一些资源清理工作(如关闭非JVM管理的原生资源)。
public class MyClass {
@Override
protected void finalize() throws Throwable {
try {
// 资源清理代码
} finally {
super.finalize(); // 调用父类的finalize
}
}
}
重要提示:finalize() 方法已经过时(deprecated),不推荐使用。原因如下:
- 执行时机不确定:
finalize() 的调用依赖于垃圾回收,而垃圾回收的时机是不确定的。
- 性能开销大:会延长对象的生命周期,可能导致对象经过多次GC周期才能被回收,影响内存回收效率。
- 可靠性差:不能保证一定被调用(如JVM紧急终止时)。
替代方案:现在推荐使用显式的资源管理方式。
总结对比
| 特性 |
final |
finally |
finalize |
| 性质 |
关键字(修饰符) |
关键字(代码块标识) |
Object类的方法 |
| 作用 |
修饰类、方法、变量,赋予不可变性 |
定义异常处理中必须执行的清理代码块 |
对象被GC前提供清理机会(已过时) |
| 执行时机 |
编译时/类加载时/初始化时确定 |
在try/catch块后(几乎)总是执行 |
垃圾回收时(不确定) |
|