源本科技 | 码上会

final、finally 与 finalize

2026/01/22
50
0

学习目标

  • 准确区分 final(关键字)、finally(异常处理块)和 finalize()(对象清理方法)三者的用途

  • 掌握 final 在变量、方法和类上的不同语义

  • 理解 finally 块的执行机制及其在资源管理中的作用

  • 了解 finalize() 方法的局限性及为何在现代 Java 中已被弃用

  • 能够在实际开发中正确、安全地使用这三种机制


final 关键字

final 是 Java 中用于限制修改的关键字,可应用于变量、方法和类。

final 变量:常量声明

一旦被初始化,final 变量的值不能被更改

public class FinalVariableExample {
    public static void main(String[] args) {
        int a = 5;           // 普通变量,可修改
        final int b = 10;    // final 变量,不可修改

        a++;                 // 合法
        // b++;              // 编译错误!Cannot assign a value to final variable 'b'
        
        System.out.println("a = " + a + ", b = " + b);
    }
}

注意

  • final 局部变量必须在声明时或之后初始化一次

  • 对于引用类型(如对象),final 仅保证引用不可变,但对象内部状态仍可修改。

final StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");     // 合法!对象内容可变
// sb = new StringBuilder(); // 非法!引用不可重新赋值

final 方法:禁止重写

final 修饰的方法不能被子类重写(override)

class Parent {
    final void display() {
        System.out.println("这是 final 方法");
    }
}

class Child extends Parent {
    // void display() { }  // 编译错误!Cannot override final method
}

用途:防止关键方法被意外或恶意覆盖,保障类的行为一致性。


final 类:禁止继承

final 修饰的类不能被继承

final class UtilityClass {
    public static void helper() {
        System.out.println("工具方法");
    }
}

// class SubClass extends UtilityClass { } // 编译错误!Cannot inherit from final class

典型例子:StringMathInteger 等核心类均为 final,确保安全性和不可变性。


finally

finally 是异常处理机制的一部分,用于定义无论是否发生异常都必须执行的代码,常用于资源释放。

基本语法

try {
    // 可能抛出异常的代码
} catch (Exception e) {
    // 异常处理
} finally {
    // 总是执行的清理代码
}

示例:文件操作中的资源关闭

import java.io.*;

public class FinallyExample {
    public static void main(String[] args) {
        FileReader reader = null;
        try {
            reader = new FileReader("example.txt");
            System.out.println("文件读取中...");
            int data = reader.read(); // 可能抛出 IOException
        } catch (IOException e) {
            System.out.println("读取文件失败: " + e.getMessage());
        } finally {
            if (reader != null) {
                try {
                    reader.close(); // 确保文件流关闭
                    System.out.println("文件流已关闭");
                } catch (IOException e) {
                    System.out.println("关闭文件失败");
                }
            }
        }
    }
}

执行保证:即使 trycatch 中有 returnbreak 或异常,finally 仍会执行(除非调用 System.exit())。

特殊情况:finally 中的 return

public static int getValue() {
    try {
        return 1;
    } finally {
        return 2; // 这会覆盖 try 中的 return!
    }
}

警告:在 finally 中使用 return 会掩盖异常或原始返回值,应避免。


finalize() 方法

对象销毁前的清理(已弃用)

finalize()Object 类中的一个方法,在对象被垃圾回收器(GC)回收之前由 JVM 调用,用于执行清理操作。

基本用法(仅作理解,不推荐使用)

public class FinalizeExample {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("对象即将被回收,执行清理...");
        super.finalize(); // 建议调用父类 finalize
    }

    public static void main(String[] args) {
        FinalizeExample obj = new FinalizeExample();
        obj = null;       // 对象变为不可达
        System.gc();      // 建议 JVM 执行垃圾回收(不保证立即执行)
        
        try {
            Thread.sleep(1000); // 等待 GC
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("程序结束");
    }
}

为什么 finalize() 被弃用?

Java 9 开始,finalize() 被标记为 @Deprecated,原因包括:

问题

说明

执行时间不确定

GC 何时运行不可控,finalize() 可能永不执行

性能开销大

使用 finalize() 的对象需要额外 GC 处理步骤

安全性风险

可能导致对象“复活”(在 finalize 中重新赋值引用)

不可靠

无法保证清理逻辑一定执行

替代方案

推荐使用以下方式替代 finalize()

  1. try-with-resources(自动关闭资源):

    try (FileInputStream fis = new FileInputStream("file.txt")) {
        // 使用资源
    } // 自动调用 close()
  2. 显式清理方法(如 close()dispose()):

    class Resource implements AutoCloseable {
        public void close() {
            // 清理逻辑
        }
    }
  3. Cleaner 机制(Java 9+)

    private static final Cleaner cleaner = Cleaner.create();
    private final Cleaner.Cleanable cleanable;
    
    public MyResource() {
        cleanable = cleaner.register(this, new CleanupAction());
    }

对比总结

特性

final

finally

finalize()

类型

关键字

关键字(用于异常处理)

方法(Object 类中)

作用

限制修改(变量 / 方法 / 类)

确保代码块总是执行

对象回收前的清理(已弃用)

执行时机

编译期检查

运行时(try-catch 后)

GC 回收前(不确定)

是否推荐使用

✅ 广泛使用

✅ 必要时使用

❌ 已弃用,避免使用

典型场景

定义常量、防止继承

关闭文件 / 数据库连接

(无,应使用其他机制)


重点总结

  • final 是实现不可变性封装安全的重要工具。

  • finally 是异常处理中确保资源释放的关键机制,但应避免在其中使用 return

  • finalize() 不应在现代 Java 应用中使用,应改用 try-with-resourcesAutoCloseableCleaner

  • 三者名称相似,但用途完全不同,切勿混淆。


思考题

  1. 如果一个 final 变量是对象引用,能否修改该对象的内部状态?请举例说明。

  2. try 块中执行 System.exit(0)finally 块还会执行吗?为什么?

  3. 为什么 Java 设计者决定弃用 finalize()?你认为这种设计对开发者有何影响?