java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java final finally finalize区别

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

作者:身如柳絮随风扬

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 特殊情况

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 来生难觅。

解释:

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. 总结

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

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

您可能感兴趣的文章:
阅读全文