【JavaSE】final、finally 和 finalize 有什么区别?


在这里插入图片描述

1. final

"final"是Java中的一个关键字,用于表示不可更改或不可继承的实体。它可以应用于变量、方法和类。

  1. final 变量 在Java中,如果一个变量被声明为“final”,则它将被视为常量,其值不能被修改。这意味着一旦初始化,该变量的值就不能再次更改。通常,final变量被视为常量,并且必须在声明时初始化。例如:
Copy Codefinal int MAX_VALUE = 100;
  1. final 方法 如果一个方法被声明为“final”,则子类将无法覆盖该方法。这意味着在子类中无法重写该方法以实现其自己的行为。例如:
Copy Codepublic class Animal {
    
    
    public final void move() {
    
    
        System.out.println("Animals can move");
    }
}

public class Dog extends Animal {
    
    
    public void move() {
    
     // 编译错误,无法重写 final 方法
        System.out.println("Dogs can walk and run");
    }
}
  1. final 类 如果一个类被声明为“final”,则该类不能被继承。这意味着不能创建该类的任何子类。例如:
final class Parent {
    
    
   // code
}

class Child extends Parent {
    
     // 编译错误,无法继承 final 类
   // code
}

使用final关键字将变量、方法或类标记为不可更改或不可继承,有助于确保代码的安全性和稳定性。


2. finally

"finally"是Java中的一个关键字,用于定义在try-catch块之后执行的代码块。即使在try-catch块中引发了异常,finally代码块也将始终执行,以便释放资源或完成其他清理操作。它通常与try和catch一起使用。

以下是finally使用的示例:

try{
    
    
    // 可能会引发异常的代码
}
catch(Exception e) {
    
    
    // 异常处理代码
}
finally {
    
    
    // 始终执行的代码
}

在上述代码中,try块包含可能会引发异常的代码,catch块包含捕获异常并执行适当的处理代码的语句。无论try块中是否有异常,finally块中的代码都将被执行。这有助于确保在任何情况下都可以执行必要的清理操作,例如关闭文件、数据库连接或网络资源等。

在 Java 中,finally 块中的代码总是会被执行,无论是否发生了异常,并且不管有没有 return 语句。这也是 finally 关键字的主要作用之一,用于确保在程序执行过程中必须完成的操作能够得到正确地执行,例如关闭文件或网络连接等操作。

值得注意的是,在 try-catch-finally 语句中,如果在 trycatch 块中出现了 return 语句,那么该 return 语句所携带的返回值将会被暂存起来,在 fxianinally 块中的代码执行完毕后再进行返回。而且,如果在 finally 块中也出现了 return 语句,那么它将覆盖之前的返回值,成为最终的返回结果。

在总体结构中,try块、catch块和finally块可以按照以下顺序组合使用:

try{
    
    
    // 可能会引发异常的代码
}
catch(ExceptionType1 e1) {
    
    
    // 处理 ExceptionType1 异常
}
catch(ExceptionType2 e2) {
    
    
    // 处理 ExceptionType2 异常
}
...
finally {
    
    
    // 始终执行的代码
}

总之,finally关键字用于定义始终执行的代码块,以确保必要的清理操作可以在任何情况下都会被执行。


3. finalize

在Java中,finalize()方法是一个特殊的方法,它被用来在对象被垃圾回收之前进行一些清理操作。当一个对象变成垃圾对象时,JVM会自动调用该对象的finalize()方法,来释放一些资源或执行必要的清理操作。

需要注意以下几点:

  1. finalize()方法是protected类型的方法:这意味着我们只能在同一个包或者子类中使用它。在其他地方,我们无法主动调用该方法。
  2. finalize()方法最好不要依赖它:因为垃圾回收器并不能保证什么时候会调用finalize()方法,所以不能够将其视为一种可靠的资源管理方式。更好的方式是在程序中手动维护资源,并且及时释放和关闭它们。
  3. finalize()方法会影响垃圾回收的效率:因为Java的垃圾回收机制非常复杂,所以在执行finalize()方法时会占用垃圾回收器更多的时间和内存。如果有太多的对象都实现了finalize()方法,那么可能会导致垃圾回收效率下降,从而影响程序的性能。
  4. 多个对象共享某些资源时,finalize()方法会出现问题:例如,多个Java对象共享同一个文件描述符时,如果其中一个对象的finalize()方法关闭了该文件描述符,那么其他共享该文件描述符的对象就无法再使用该文件描述符了。

综上所述,虽然finalize()方法可以用于释放资源、关闭文件等操作,但是它并不是一种可靠的资源管理方式。在实际开发中,最好手动维护资源,并且及时释放和关闭它们,以免出现意外问题。

如果,在执行完finalize()方法之后,如果该对象重新被引用,那么它就会“复活”。

具体来说,当一个对象变成垃圾对象时,JVM会调用该对象的finalize()方法进行清理操作。如果在finalize()方法执行期间,该对象被重新引用了,那么这个对象就不再是垃圾对象了,即它被“复活”了。例如:

public class Example {
    
    
    private static Example instance;

    public void finalize() {
    
    
        System.out.println("Object is being finalized");
        instance = this;
    }

    public static void main(String[] args) {
    
    
        Example obj1 = new Example();
        obj1 = null;
        //触发GC
        System.gc();

        try {
    
    
            Thread.sleep(1000);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        if (instance != null) {
    
    
            System.out.println("Object is not null");
        } else {
    
    
            System.out.println("Object is null");
        }
    }
}

在该例子中,Example类实现了finalize()方法,并且在该方法中将instance变量设置为当前对象。然后,我们创建了一个Example对象,将其赋值为null,并强制执行垃圾回收。在等待一段时间后,我们检查instance变量是否为空。

由于finalize()方法将instance变量设置为当前对象,所以在垃圾回收器执行finalize()方法时,该对象被复活了。因此,在等待一段时间后,instance变量不为空,输出为“Object is not null”。

需要注意的是,即使对象被复活了,它也不会完全恢复到之前的状态,因为它的所有成员都已经失效。因此,在实际开发中,我们应该尽量避免使用finalize()方法来进行资源管理和清理操作,以免出现意外问题。


猜你喜欢

转载自blog.csdn.net/weixin_51146329/article/details/129882279