Java中final、finally和finalize的区别

简介:

“final、finally和finalize有什么区别?”, 这是一道再经典不过的面试题了,我们在各个公司的面试题中几乎都能看到它的身影。final、finally和finalize虽然看起来很像,含义也差不多(字根都是final),但是它们的用法是不同的。本节主要来讨论一下它们在实际场景中的运用。

final用法说明:

是java关键字之一,用于修饰类或者方法,或者变量,可以和static共存。
被fianl修饰的这些类,方法,变量都不能再被修改。对于类,不能再被继承;对于方法,不能被重写;对于基本类型的变量,不能修改其值(其实就是常量);

对于引用类型(即final修饰的是一个对象的情形),就表示这个变量被赋予的引用是不可变的,注意,不可改变的只是这个变量所保存的引用,并不是这个引用所指向的对象。

一个类不能既被abstract声明,又被final声明,这是因为被final修饰的类,就意味着不能再派生出新的子类,不能作为父类而被子类继承,这和abstract正好是互斥的。

被final修饰的变量必须被初始化。初始化方式:
在定义的时候初始化。
final变量可以在初始化块中初始化,不可以在静态初始化块中初始化。
静态final变量可以在静态初始化块中初始化,不可以在初始化块中初始化。
final变量还可以在类的构造器中初始化,但是静态final变量不可以。

final用来修饰一个变量:

程序举例:

package demo.test.my;

public class BydCar {

    // 非静态final变量在定义时初始化
    public final String tagName = "BydCar";

    //非静态final变量可以在静态初始化块中初始化
    public final int tagId;
    // 在初始化块中初始化
    {
        tagId = 10000;
    }

    // 非静态final变量不能在静态初始化块中初始化
    // public final int C;
    // static {
    // C = 30;
    // }

    // 静态常量,在定义时初始化
    public static final float Min_Value = 0;

    public static final float Max_Value;
    // 静态常量,在静态初始化块中初始化
    static {
        Max_Value = 200.0f;
    }

    // 静态变量不能在初始化块中初始化
    // public static final int Max_Value;
    // {
    // Max_Value = 200.0f;
    // }

    //非静态final变量可以在构造器中初始化
    public final int code;

    // 静态final变量不可以在构造器中初始化
    // public static final int code;

    // 在构造器中初始化
    public BydCar() {
        code = 666666; //非静态final变量可以在构造器中初始化
        // 静态final变量不可以在构造器中初始化
        // code = 777777;

        // 给final的变量第二次赋值时,编译会报错
         //code = 888888;   //Variable 'G' might already have been assigned to
    }

    // final变量未被初始化,编译时就会报错
    //public final int I;   //编译错误:Variable 'I' might not have been initialized

    // 静态final变量未被初始化,编译时就会报错
    //public static final int STATIC_J;  //编译错误: Variable 'STATIC_J' might not have been initialized
}

运行上面的代码之后出了可以发现final变量(常量)和静态final变量(静态常量)未被初始化时,编译会报错;
另外还可以发现,静态final变量可以在构造器中初始化,却不可以在初始化块中初始化。 

final用来修饰一个方法:

程序举例:

BaseClass.java:

package demo.test.my;

public class BaseClass {
    //
    public final void fun() {
        System.out.println("[BaseClass] fun be call!");
    }
}

SubClass.java:继承自BaseClass

package demo.test.my;

public class SubClass extends BaseClass {
    /**
     * 子类无法重写(override)父类的final方法fun,否则编译时会报错:
     * 'fun()' cannot override 'fun()' in 'demo.test.my.BaseClass'; overridden method is final
     */
//     public void fun() {
//         System.out.println("[SubClass]子类--重写final方法");
//     }

    public static void main(String[] args) {
        SubClass sc = new SubClass();
        sc.fun(); //调用弗雷的fun
    }
}

运行结果:

[BaseClass] fun be call!
 

这里需要特殊说明的是,具有private访问权限的方法也可以增加final修饰,但是由于子类无法继承private方法,因此也无法重写它。

finally的用法:

finally是java的关键字,用在try-catch-finally,最终被执行的代码放在finally语句块中。

注意,return、continue和break都无法阻止finally语句块的执行。

finally的代码示例:

package demo.test.my;

public final class F0Car {
    public static void main(String[] args) {
        try {
            throw new NullPointerException();
        } catch (NullPointerException e) {
            System.out.println("程序抛出了异常");
            return;
        } finally {
            System.out.println("执行了finally语句块");
        }
    }
}

运行结果:

程序抛出了异常
执行了finally语句块

finalize的用法:

finalize不是java关键字,而是一个方法,属于java.lang.Object类的一个方法,它的定义如下:

protected void finalize() throws Throwable { }

finalize()方法是在GC清理它所从属的对象时被JVM自动调用的,如果执行它的过程中抛出了无法捕获的异常(uncaught exception),GC将终止对改对象的清理,并且该异常会被忽略;直到下一次GC开始清理这个对象时,它的finalize()会被再次调用。

finalize的代码示例:

package demo.test.my;

public final class F0Car {
    // 重写finalize()方法
    protected void finalize() throws Throwable {
        System.out.println("F0Car::finalize()"); //输出:F0Car::finalize()
    }

    public static void main(String[] args) {
        F0Car car = new F0Car();
        car = null;
        System.gc();
    }
}

运行结果:

F0Car::finalize()

 分析:

程序调用了java.lang.System类的gc()方法,引起GC的执行,GC在清理ft对象时调用了它的finalize()方法,因此才有了上面的输出结果。调用System.gc()等同于调用下面这行代码:

Runtime.getRuntime().gc();

调用它们的作用只是建议垃圾收集器(GC)启动,清理无用的对象释放内存空间,但是GC的启动并不是一定的,这由JAVA虚拟机来决定。


### Javafinalfinallyfinalize区别及用法 #### 1. `final`关键字 - **修饰类**: 当一个类被声明为`final`时,表示该类不能被继承。这意味着任何试图继承该类的行为都会导致编译错误[^5]。 - **修饰方法**: 被`final`修饰的方法不能在子类中被重写(覆盖)。这可以确保方法的行为在继承体系中保持不变[^3]。 - **修饰变量**: 当`final`用于修饰变量时,表示该变量的值一旦被初始化后就不能再被改变。对于基本数据类型,这意味着其值不可变;对于引用类型,则表示该引用不能再指向其他对象,但对象本身的内容仍可修改[^5]。 ```java // final修饰类 final class FinalClass { // 类内容 } // final修饰方法 class Parent { final void show() { System.out.println("This is a final method."); } } // final修饰变量 final int FINAL_VAR = 10; ``` #### 2. `finally`关键字 - `finally`通常与`try-catch`块一起使用,用于定义一段无论是否发生异常都必须执行的代码。即使在`try`或`catch`块中存在`return`语句,`finally`块中的代码仍然会被执行[^2]。 - `finally`的主要用途是释放资源,例如关闭文件流或网络连接等操作。 ```java try { // 可能抛出异常的代码 } catch (Exception e) { // 处理异常 } finally { // 必须执行的代码 System.out.println("Finally block executed."); } ``` #### 3. `finalize`方法 - `finalize`是一个特殊的方法,由`Object`类定义,可以在对象被垃圾回收器回收之前调用。它提供了一个机会来执行清理工作,例如释放外部资源[^4]。 - 然而,`finalize`方法的调用时间是不确定的,依赖于垃圾回收器的行为。因此,不建议依赖`finalize`来进行关键的资源管理[^4]。 ```java protected void finalize() throws Throwable { try { // 清理资源 System.out.println("Finalize method called."); } finally { super.finalize(); } } ``` ### 注意事项 - `final`主要用于确保某些行为或状态不可改变,从而提高程序的安全性性能。 - `finally`块总是会被执行,除非JVM退出或程序被强制终止[^2]。 - `finalize`方法的存在并不意味着对象一定会被垃圾回收,且其调用时机无法预测。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

liranke

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值