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虚拟机来决定。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

liranke

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

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

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

打赏作者

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

抵扣说明:

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

余额充值