深入理解Java中关键字final、finally、finalize的区别

 更新时间:2026年05月27日 08:37:34   作者:身如柳絮随风扬  
final、finally、finalize 的区别 这三个 Java 关键字虽然拼写相似,但功能完全不同,本文将从定义、使用场景、代码示例、底层机制以及最佳实践等多个维度,彻底讲清这三者的差异,并附上流程图和对比表格,助你一次搞懂

1. 引言

在 Java 面试中,有一个经典问题频繁出现:“请说说 final、finally 和 finalize 的区别”。这三个关键字拼写相似,但含义和作用截然不同。理解它们的区别,不仅有助于写出更健壮的代码,也是衡量 Java 基础是否扎实的重要标尺。

本文将从定义、使用场景、代码示例、底层机制以及最佳实践等多个维度,彻底讲清这三者的差异,并附上流程图和对比表格,助你一次搞懂。

2. 三者的核心区别速览

关键字所属范畴主要作用典型使用场景
final关键字/修饰符限制类、方法、变量不可变常量定义、防止继承/重写
finally异常处理块无论是否异常,保证代码执行释放资源(关闭文件、数据库连接等)
finalizeObject 类方法对象被垃圾回收前调用(已过时)对象临终清理(不推荐)

3. final:不可变的守护者

final 是一个修饰符,可以用于修饰类、方法、变量。一旦被 final 修饰,其特性便“固定”下来。

3.1 final 修饰类

final 修饰的类不能被继承。这通常用于那些设计上不允许扩展的类,例如 StringInteger 等包装类。

public final class Constants {
    // 类体
}

// 编译错误:无法继承 final 类
// class MyConstants extends Constants { }

3.2 final 修饰方法

final 修饰的方法不能被重写(Override)。这可以防止子类修改父类的关键行为。

class Parent {
    public final void doSomething() {
        System.out.println("Parent action");
    }
}

class Child extends Parent {
    // 编译错误:无法重写 final 方法
    // public void doSomething() { }
}

3.3 final 修饰变量

  • 基本类型变量:一旦赋值,值不可改变,成为常量。
  • 引用类型变量:引用地址不可改变,但对象内部状态仍可修改。
  • 成员变量:必须在声明时、构造器或初始化块中显式赋值。
  • 局部变量:在使用前赋值即可,之后不可修改。
final int MAX_COUNT = 100;          // 常量
final List<String> list = new ArrayList<>();
list.add("hello");                  // ✅ 允许(对象内容可变)
// list = new ArrayList<>();        // ❌ 编译错误,引用地址不可变

最佳实践:使用 static final 定义真正的全局常量(命名全大写、下划线分隔)。

4. finally:保证执行的最后防线

finally 是异常处理机制的一部分,与 trycatch 配合使用。它的特点是:无论 try 块中是否发生异常,finally 块中的代码都会被执行(除非 JVM 退出或当前线程被中断)。

4.1 基本语法

try {
    // 可能抛出异常的代码
} catch (Exception e) {
    // 处理异常
} finally {
    // 一定会执行的代码,通常用于释放资源
    // 例如:关闭文件流、数据库连接、网络连接等
}

4.2 典型场景:资源释放

FileInputStream fis = null;
try {
    fis = new FileInputStream("test.txt");
    // 读取文件...
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (fis != null) {
        try {
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意:Java 7 引入了 try-with-resources,可以更优雅地实现自动资源释放(要求资源类实现 AutoCloseable)。但 finally 仍然是通用异常清理模式的基础。

4.3 特殊情况

  • 如果 trycatch 中执行了 System.exit(0),则 finally 不会执行
  • 如果 finally 块中抛出了未被处理的异常,它会覆盖 trycatch 中抛出的原始异常。

5. finalize:被遗忘的临终方法

finalize()java.lang.Object 类中定义的一个 protected 方法。当垃圾回收器(GC)确定某个对象“没有引用”时,会先调用该对象的 finalize() 方法(如果被重写),然后再回收对象的内存。

5.1 基本用法(已过时)

public class MyResource {
    @Override
    protected void finalize() throws Throwable {
        try {
            // 释放本地资源(如关闭文件句柄)
            System.out.println("finalize called");
        } finally {
            super.finalize();
        }
    }
}

5.2 为什么 finalize 已被标记为废弃(deprecated)?

问题说明
不确定性GC 何时调用 finalize() 不可预知,甚至永远不会被调用(如果对象永远不被 GC)。
性能开销重写 finalize() 会显著增加 GC 开销(对象需要两次标记)。
顺序问题finalize() 执行顺序不受控制,可能导致资源访问冲突。
替代方案使用 try-with-resourcesCleaner(Java 9+)或显式资源管理方法(如 close())。

自 Java 9 起,finalize() 已被正式标记为 deprecated(弃用),建议永远不要在新代码中使用它。

5.3 对象死亡流程(含 finalize)

从流程图可以看出,finalize() 甚至可能导致对象“复活”(在 finalize() 中重新将自己赋值给某个静态变量),这是非常危险的行为,也是它被弃用的原因之一。

6. 综合对比与记忆口诀

6.1 对比表格

维度finalfinallyfinalize
类型关键字关键字方法名
所在包语言核心语言核心java.lang.Object
主要作用定义不可变性异常后清理对象临终处理(已过时)
可修饰目标类、方法、变量代码块对象实例方法
是否推荐使用✅ 大量使用✅ 推荐❌ 强烈不推荐

6.2 记忆口诀

final 定终(终态)身不二,finally 生死不离,finalize 来生难觅。

解释:

  • final 锁定类的继承、方法的重写、变量的改变。
  • finally 无论生死(异常与否)都会执行。
  • finalize 被垃圾回收调用,但时机不定,如今已“难觅”踪影。

7. 代码示例:三者的协作

以下示例展示了在一个方法中同时使用 final 变量、finally 块以及 finalize 方法(仅为演示,实际不推荐):

public class TestFinalFinallyFinalize {

    // final 常量
    private static final String MESSAGE = "Hello";

    public static void main(String[] args) {
        // final 局部变量
        final int times = 1;
        try {
            System.out.println(MESSAGE + " for " + times + " time");
            // 模拟异常
            // throw new RuntimeException();
        } finally {
            System.out.println("finally block: always executed");
        }
    }

    // 不推荐重写 finalize
    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalize called (deprecated)");
        super.finalize();
    }
}

输出(正常情况):

Hello for 1 time
finally block: always executed

finalize() 通常不会被调用,因为程序退出时对象可能不一定会被 GC。

8. 总结

  • final:不可变修饰符,用来定义常量、阻止继承和重写。
  • finally:异常处理中的保证执行块,用于释放资源等清理工作。
  • finalize:已被废弃的对象回收前回调方法,不要在新代码中使用。

掌握这三者的区别,是 Java 基础学习中的重要里程碑。最后提醒:如果你面试时被问到 finalize,最好能主动说明它已被标记为过时,并推荐使用 try-with-resourcesCleaner 作为替代方案,这将展示你对 Java 现代特性的了解。

到此这篇关于深入理解Java中关键字final、finally、finalize的区别的文章就介绍到这了,更多相关Java final finally finalize区别内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java中对象为null时的打印输出方式

    java中对象为null时的打印输出方式

    这篇文章主要介绍了java中对象为null时的打印输出方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • Java中两个List之间的比较方法(差集、交集和并集)

    Java中两个List之间的比较方法(差集、交集和并集)

    在业务的开发过程中会经常用到两个List集合相互取值的情况,下面这篇文章主要给大家介绍了关于Java中两个List之间的比较方法,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • 聊聊Redis二进制数组Bitmap

    聊聊Redis二进制数组Bitmap

    这篇文章主要介绍了Redis二进制数组Bitmap,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • SpringBoot中实现多线程六种方式大全

    SpringBoot中实现多线程六种方式大全

    Spring Boot 提供了非常丰富的多线程支持手段,从最简单的注解到虚拟线程,可以满足从简单异步任务到高并发 IO/CPU 密集型场景的各种需求,下面列出目前(2026 年视角)最常用、最推荐的 6 种方式,需要的朋友可以参考下
    2026-02-02
  • java随机生成一个名字和对应拼音的方法

    java随机生成一个名字和对应拼音的方法

    这篇文章主要介绍了java随机生成一个名字和对应拼音的方法,涉及java针对数组及随机数操作的相关技巧,需要的朋友可以参考下
    2015-07-07
  • JAVA中六种策略模式的实现方式(附代码示例和适用场景)

    JAVA中六种策略模式的实现方式(附代码示例和适用场景)

    策略模式是一种行为模式,也是替代大量ifelse的利器,它所能帮你解决的是场景,一般是具有同类可替代的行为逻辑算法场景,这篇文章主要介绍了JAVA中六种策略模式实现方式的相关资料,需要的朋友可以参考下
    2026-01-01
  • SpringBoot的@GetMapping路径匹配规则、国际化详细教程

    SpringBoot的@GetMapping路径匹配规则、国际化详细教程

    这篇文章主要介绍了SpringBoot的@GetMapping路径匹配规则、国际化,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-11-11
  • 详解Mybatis 传递参数类型为List的取值问题

    详解Mybatis 传递参数类型为List的取值问题

    这篇文章主要介绍了详解Mybatis 传递参数类型为List的取值问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • 解决Android Studio安装后运行出错dose not...和Internal error...

    解决Android Studio安装后运行出错dose not...和Internal error...

    这篇文章主要介绍了解决Android Studio安装后运行出错dose not...和Internal error...的相关资料,需要的朋友可以参考下
    2017-03-03
  • 解读RabbitMQ和kafka的相同点和不同点是什么

    解读RabbitMQ和kafka的相同点和不同点是什么

    RabbitMQ和Kafka都是消息中间件,支持分布式系统、高可用性和可靠性,RabbitMQ使用队列模型,适合复杂路由场景;Kafka使用主题-分区模型,适合大规模数据流处理,RabbitMQ在低延迟方面表现更好,Kafka在高吞吐量方面表现更好
    2024-12-12

最新评论