高频面试题final、finally、finalize 有什么区别?

98 阅读3分钟

概述

在Java中,final、finally和finalize前两个具是有不同含义和用途的关键字,而finalize 是Object类中的一个方法

final介绍

final 关键字用于修饰类、方法和变量。当类被声明为final时,表示它是最终类,不能被继承。当方法被声明为final时,表示它是最终方法,不能被子类重写。当变量被声明为final时,表示它是最终变量,即常量,一旦赋值后不能再次修改。

final 用法说明

  • 当 final 修饰类时,此类不允许被继承,表示此类设计的很完美,不需要被修改和扩展。
  • 当 final 修饰方法时,此方法不允许任何从此类继承的类来重写此方法,表示此方法提供的功能已经满足当前要求,不需要进行扩展。
  • 当 final 修饰变量时,表示该变量一旦被初始化便不可以被修改。
  • 当 final 修饰参数时,表示此参数在整个方法内不允许被修改。

final 用法示例


public final class MyClass {  // 声明一个最终类
    public final int MAX_VALUE = 100;  // 声明一个最终变量

    public final void printMessage() {  // 声明一个最终方法
        System.out.println("Hello, World!");
    }
}

在这个示例中,MyClass 类被声明为最终类,意味着不能被继承。MAX_VALUE 变量被声明为最终变量,即常量,一旦赋值后不能再次修改。printMessage 方法被声明为最终方法,不能被子类重写。

finally介绍

finally关键字用于异常处理中的finally块。无论是否抛出异常,finally块中的代码总会被执行。通常用于释放资源或确保某些操作的必要执行,比如关闭数据库连接、关闭文件等。

在以下 4 种特殊情况下,finally块不会被执行:

  • finally 语句块中发生了异常。
  • 在前面的代码中用了 System.exit() 退出程序。
  • 程序所在的线程死亡。
  • 关闭 CPU 。

finally 用法示例

public class FileHandler {
    public void openFile(String fileName) {
        try {
            // 打开文件
            // 进行文件操作
        } catch (IOException e) {
            // 处理异常
        } finally {
            // 无论是否发生异常,都会执行的代码块
            // 释放资源或确保必要操作的执行
        }
    }
}

openFile 方法中,我们打开一个文件并进行一些操作。在 try-catch 块中,我们可以捕获可能发生的 IOException 异常并进行相应的处理。而在 finally 块中,我们可以放置一些资源释放的代码,无论是否发生异常,这些代码都会被执行。

finalize介绍

finalize方法是Object类中的一个方法,它在垃圾回收器对对象进行垃圾回收前会被调用。子类可以重写finalize方法来定义自己的垃圾回收行为,例如释放非Java堆内存资源。但是,由于finalize方法的触发时间是不确定的,不建议过多地依赖它来进行资源的释放和清理。

finalize用法示例

public class MyObject {
    @Override
    protected void finalize() throws Throwable {
        try {
            // 执行一些资源的释放或清理操作
        } finally {
            super.finalize();
        }
    }
}

在这个示例中,MyObject 类重写了 finalize 方法。在这个方法中,我们可以编写释放资源或清理操作的代码。需要注意的是,最后要调用 super.finalize() 方法以确保正确地进行垃圾回收的处理。

finalize 性能问题

finalize 除了执行“不稳定”之外,还有一定的性能问题。 ​

因为 finalize 的执行是和垃圾收集关联在一起的,一旦实现了非空的 finalize 方法,就会导致相应对象回收呈现数量级上的变慢,有人专门做过 benchmark,大概是 40~50 倍的下降。 ​

因为 finalize 被设计成在对象被垃圾收集前调用,这就意味着实现了 finalize 方法的对象是个“特殊公民”,JVM 要对它进行额外处理。finalize 本质上成为了快速回收的阻碍者,可能导致你的对象经过多个垃圾收集周期才能被回收。