Java中final、finally和finalize的区别与正确用法

小满
小满
发布时间:2026-10-16| 7人浏览过
原创

在Java开发中,final、finally和finalize这三个词汇极易混淆,但它们在语言中的角色截然不同。本文将清晰区分这三者:final是用于声明不可变的关键字,修饰类、方法和变量;finally是异常处理结构中保证代码执行的机制;而finalize则是已过时的对象销毁回调方法。了解它们的差异对于编写稳健的Java代码至关重要。

1. final:表示不可变的修饰关键字

final是Java语言的核心关键字之一,主要用途是确保某项内容一旦被定义就无法被修改。它可以应用于类、方法、变量和方法参数四个层面,从根本上改变了这些元素的生命周期和可修改性。

第1步:理解 final 的核心作用

在编程实践中,使用 final 通常出于以下目的:

  • 数据完整性:确保常量或状态在初始化后不会被意外篡改。
  • 设计封闭性:防止类被继承或方法被子类重写,实现严格的API契约。

第2步:final 的具体应用场景与代码示例

根据应用目标的不同,final 的使用方式如下所示:

1. 修饰类(Class)

当 final 修饰一个类时,该类成为最终类,不允许被任何子类继承。这通常用于设计那些逻辑已经完备、不需要扩展的类,例如Java标准库中的 String 类就是 final 的,以确保其行为的一致性。

// 此类无法被继承
final class Animal {
    // ...
}

2. 修饰方法(Method)

在父类中定义为 final 的方法,其子类无法对该方法进行重写(Override)。这确保了该类提供的核心功能在所有继承层级中都保持固定不变,不会被子类逻辑破坏。

public class FinalExample {
    public final void sayHi() {
        System.out.println("Hi~");
    }
}

3. 修饰变量(Variable)

无论是成员变量、局部变量还是静态变量,加上 final 后都变成了常量(Constant)。变量必须在声明时或构造器内完成初始化,且一旦赋值便不可更改。这对于多线程环境下的安全访问尤为重要。

public class FinalExample {
    private static final String MSG = "hello";
    // ...
}

4. 修饰方法参数(Parameter)

这是一个容易被忽视的特性。将参数标记为 final 意味着在方法体内部不能重新为该参数赋值。这在Lambda表达式或匿名类中非常有用,确保捕获的变量符合函数式编程的要求。

public class FinalExample {
    public void sayHi(final String name) {
        // name = "newName"; 如果这样做会编译错误
        System.out.println("Hi," + name);
    }
}

2. finally:保障关键代码必定执行的机制

在实际应用中,程序不可避免地会抛出异常。为了确保在业务流程中断时,系统仍能正确恢复(例如关闭数据库连接、释放文件句柄),我们需要使用异常处理结构中的 finally 关键字。

第1步:掌握 try-catch-finally 的标准结构

finally 块中的代码具有极强的强制性,无论前面的 try 块是否发生异常,也无论异常是否被 catch 块捕获,finally 块中的代码都一定会被执行。这正是其在处理资源清理时的核心价值所在。

典型的资源管理流程如下:

try {
    // 可能会引发异常的代码
} catch (Exception e) {
    // 处理异常
} finally {
    // 无论结果如何都会执行的代码,如关闭连接
}

第2步:明确 finally 的执行边界

虽然 finally 的执行率极高,但它并非绝对无懈可击。在极少数特定极端情况下,finally 块中的代码可能根本得不到执行机会。面试官常以此测试对JVM底层运行环境的理解:

  1. 如果在 try 或 catch 块中调用了 System.exit(0),JVM会被强制终止,finally 不会执行。
  2. 如果在 try 或 catch 块中发生了死锁、断电源等导致JVM进程完全消失的硬件级故障。
  3. 如果在 try 或 catch 块所在的线程被强力杀掉(Thread.stop等不推荐的操作)。

下面这张图展示了在正常逻辑流和特殊阻断情况下的执行差异:

除了上述极端情况,在任何标准的 return、throw 或异常跳转操作中,finally 都会在控制流真正离开当前方法前执行。因此,它是保证资源安全的最佳位置。

3. finalize:已被弃用的对象销毁钩子

与 final 和 finally 不同,finalize() 是 Java 基类 Object 中的一个非静态方法。它的设计初衷是为程序员提供一个“最后的机会”,以便在对象被垃圾收集器(GC)回收之前,执行某些特定的清理工作。

第1步:为什么现在不推荐使用 finalize?

finalize 方法在很长一段时间内被视为一种糟糕的设计模式,主要原因在于其执行结果的极度不可预测性:

  • 执行时机不确定:JVM 并不保证何时进行垃圾回收。如果一个对象即将被回收,它的 finalize 方法可能永远不会被调用,或者在极长时间后才被调用。
  • 存在风险:如果对象在 finalize 方法中将自己重新引用到一个活跃对象(Re-stealing),该对象将逃脱垃圾回收的命运,这不仅浪费内存,还可能导致严重的系统问题。

第2步:不可忽视的性能损耗

除了不可靠性,finalize 还会带来显著的性能降级。由于实现了 finalize 方法的对象在回收机制上被视为“特殊公民”,垃圾收集器必须对其进行额外的生命周期跟踪和处理。

研究表明,包含 finalize 方法的对象,其回收速度大约会比普通对象慢 40~50 倍。这意味着这些对象可能需要经历多次GC扫描才能被彻底清除,极大地降低了系统的吞吐量和响应能力。基于这些原因,从 JDK 9 开始,官方已将其正式标记为 deprecated(已弃用)。

4. 总结

为了清晰记忆,我们可以这样区分:final 用来“锁定”类和变量,使其不可变;finally 用来“兜底”,保证关键的清理代码无论如何都会运行;而 finalize 则是一个早已被证实弊大于利的旧方法,在现代 Java 开发中应当坚决避免依赖它来释放资源。如果需要管理外部资源,建议使用 try-with-resources 语句。

以上就是Java中final、finally和finalize的区别与正确用法的详细内容,更多关于Java高级特性优化的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。