final、finally、finalize 的区别

参考回答**

在Java中,finalfinallyfinalize 是三个完全不同的概念,尽管名字相似,但它们分别用于变量、代码块和对象生命周期,其含义和使用场景也各不相同:

  1. final:一个关键字,用于修饰类、方法和变量,表示不能被修改或继承。
  2. finally:一个代码块,常与try-catch一起使用,表示无论是否发生异常,都一定会执行的代码。
  3. finalize:一个方法,用于垃圾回收时对对象进行清理操作,但很少使用。

详细讲解与拓展

1. final

final是一个修饰符,可以用来修饰类、方法和变量,含义如下:

  • 修饰类:被修饰的类不能被继承。
  • 修饰方法:被修饰的方法不能被子类重写。
  • 修饰变量:被修饰的变量是常量,初始化后值不能被修改。

例子:

// 修饰类
final class Animal {
    // ...
}
// class Dog extends Animal {} // 编译错误,因为Animal是final类

// 修饰方法
class Animal {
    final void sound() {
        System.out.println("Animal sound");
    }
}
class Dog extends Animal {
    // void sound() {} // 编译错误,无法重写final方法
}

// 修饰变量
class Example {
    public static void main(String[] args) {
        final int a = 10;
        // a = 20; // 编译错误,final变量的值不能被修改
    }
}

注意

  • final
    

    修饰引用类型时,引用地址不能被修改,但引用指向的对象内容是可以修改的。

    final List<String> list = new ArrayList<>();
    list.add("Hello"); // 允许
    // list = new ArrayList<>(); // 编译错误
    

2. finally

finally是一个代码块,用于保证无论try代码块是否抛出异常,某些必要的清理工作(如释放资源、关闭文件)一定会执行。

特点:

  • finally代码块与try-catch配合使用。
  • 即使try中有return语句,finally仍会执行。
  • 唯一不会执行finally的情况是:程序在trycatch中使用了System.exit(0)终止程序。

例子:

public class Example {
    public static void main(String[] args) {
        try {
            System.out.println("Inside try block");
            int result = 10 / 0; // 触发异常
        } catch (ArithmeticException e) {
            System.out.println("Exception caught: " + e.getMessage());
        } finally {
            System.out.println("Finally block executed");
        }
    }
}

输出:

Inside try block
Exception caught: / by zero
Finally block executed

finally中的代码始终会执行:

public class Example {
    public static void main(String[] args) {
        System.out.println(testFinally());
    }
    static int testFinally() {
        try {
            return 1; // 尝试返回
        } finally {
            System.out.println("Finally block executed");
            return 2; // 最终返回值被覆盖为2
        }
    }
}

输出:

Finally block executed
2

常见用途:

  • 用于关闭资源,如文件、数据库连接等:
    try {
      BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
      // 读取文件操作
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      reader.close(); // 无论如何都要关闭文件
    }
    

3. finalize

finalizeObject类的一个方法,它在垃圾回收器(GC)回收对象之前被调用,用于进行资源回收或清理工作。

特点:

  • 每个类都可以重写finalize方法,用于释放对象占用的资源,比如文件句柄、网络连接等。
  • 不推荐使用,因为Java的垃圾回收机制已经能很好地管理资源,finalize增加了GC的开销,效率较低,且行为不确定(调用时间不确定)。

例子:

class Example {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("Finalize method called");
    }
    public static void main(String[] args) {
        Example obj = new Example();
        obj = null; // 使对象变成垃圾
        System.gc(); // 提示JVM进行垃圾回收
        System.out.println("End of program");
    }
}

输出:

End of program
Finalize method called

注意

  • System.gc()只是建议JVM进行垃圾回收,实际是否执行finalize方法取决于JVM实现。
  • finalize方法已被逐步废弃,从Java 9开始被标记为deprecated,Java 14中被彻底移除。

替代方案: 对于资源清理任务,推荐使用try-with-resources语句或显式的关闭方法。


总结对比

特性 final finally finalize
用法 修饰类、方法或变量 一个代码块,用于资源清理或最终执行代码 一个方法,用于对象被垃圾回收前的清理工作
位置 用于类定义、方法定义、变量定义 用于try-catch 定义在Object类中,可被子类重写
执行时机 编译时生效 程序运行时,try-catch块结束后执行 垃圾回收时被调用,时间不确定
功能 防止修改、重写、继承 保证必要代码一定会执行 资源回收或清理工作,但不推荐使用
推荐程度 推荐,广泛使用 推荐,特别适合资源清理操作 不推荐,从Java 9开始被废弃,建议使用try-with-resources

总结

  1. final
    • 防止变量值被修改(常量)。
    • 防止方法被重写。
    • 防止类被继承。
  2. finally
    • 用于资源清理或释放,无论是否发生异常都会执行。
  3. finalize
    • 用于垃圾回收前的清理工作,但不推荐使用,取而代之的是try-with-resources或显式关闭资源方法。

发表回复

后才能评论