1. final、finally、finalize 的区别
final:
用途:用于修饰类、方法和变量。
final class ImmutableClass {
}
class Parent {
final void method() {
}
}
final int MAX_VALUE = 100;
final List<String> list = new ArrayList<>();
特点:
- 不可变性:
final
修饰的变量在初始化后不能被重新赋值。 - 性能优化:
final
方法和变量可能被 JVM 优化,例如内联展开。 - 线程安全:
final
修饰的变量在多线程环境中可以减少同步开销。
实践建议:
- 使用
final
修饰类和方法可以防止意外修改,增强代码的安全性。 - 使用
final
修饰变量可以避免意外赋值,提高代码的可读性和维护性。
finally:
- 用途:用于确保在
try
块中的代码执行完毕后,无论是否发生异常,finally
块中的代码都会被执行。try {
FileInputStream file = new FileInputStream("data.txt");
} catch (IOException e) {
System.out.println("文件读取异常");
} finally {
if (file != null) {
file.close();
}
}
- 特点:
- 保证执行:
finally
块中的代码在 try 块执行完毕后一定会被执行,即使发生异常、try
或catch
中有return
语句。 - 资源释放:常用于释放资源,如关闭文件流、数据库连接等。
- 实践建议:
- 使用 try-finally 或 try-catch-finally 结构来确保资源的正确释放。
- 在
finally
块中避免执行可能导致程序异常的代码,以免掩盖真正的异常。 - Java 7+推荐使用try-with-resources替代
finally
手动关闭资源
try (FileInputStream file = new FileInputStream("data.txt")) {
} catch (IOException e) {
}
finalize:
- 用途:
finalize
是 Object
类的一个方法,用于在对象被垃圾收集器回收前执行一些清理工作。
public class ResourceHolder {
@Override
protected void finalize() throws Throwable {
System.out.println("对象即将被回收");
super.finalize();
}
}
- 特点:
不可预测性:finalize
的执行时间和顺序是不可预测的,依赖于垃圾收集器的行为。
性能问题:实现finalize
方法的对象在垃圾收集时会增加额外的开销,可能导致性能下降。
已废弃:从 JDK 9 开始,finalize
方法被标记为 @Deprecated
,不推荐使用。 - 实践建议:
避免使用 finalize
方法进行资源回收,推荐使用 try-with-resources 或 AutoCloseable
接口。
如果确实需要在对象销毁时执行某些操作,可以考虑使用java.lang.ref.Cleaner
机制。
2. 实践建议
- 使用 final:
- 明确表示代码的语义和逻辑意图,避免意外修改。
- 保护只读数据,减少线程同步开销。
- 但不要过度依赖 final 带来的性能优化,现代 JVM 已经非常智能。
- 使用 finally:
- 确保资源的正确释放,避免资源泄漏。
- 推荐使用 try-with-resources 语句来简化资源管理。
- 避免使用 finalize:
- finalize 存在性能问题和不可预测性,不推荐使用。
- 使用 Cleaner 机制或其他替代方案进行资源回收。
3. 知识扩展
- final 不是 immutable:
- final 只能约束变量的引用不被重新赋值,但对象本身的行为不受影响。
- 如果需要实现不可变对象,需要确保类的成员变量是 private 和 final,并且实现深度拷贝。
- finalize 的问题:
- finalize 的执行时间和顺序不可预测,可能导致资源泄漏和性能问题。
- finalize 中的异常会被生吞,导致难以诊断的问题。
- Cleaner 机制:
- Cleaner 利用幻象引用(PhantomReference)和引用队列实现资源回收,比 finalize 更可靠。
- Cleaner 的操作是独立的,避免了 finalize 中的死锁问题。
4. 对比总结
特性 | final | finally | finalize |
---|
类型 | 修饰符(关键字) | 代码块(关键字) | 方法(定义在Object类中) |
作用 | 定义不可变的类、方法或变量 | 确保代码块在异常处理中始终执行 | 在对象被回收前执行清理操作(不推荐使用) |
使用场景 | 常量定义、禁止继承或重写 | 资源释放(如关闭文件、数据库连接) | 历史遗留的清理逻辑(实际应避免使用) |
确定性 | 编译时强制约束 | 运行时保证执行 | 执行时机由JVM决定,不可控 |
推荐实践 | 广泛用于增强代码安全性 | 优先用try-with-resources替代 | 避免使用,改用显式资源管理 |