JAVA核心技术36讲_第3讲 谈谈final、finally、finalize的区别?

129 阅读3分钟

谈谈final、finally、finalize的区别?

典型回答

final可以用来修饰类、方法、变量,分别有不同的意义,final修饰类代表不可继承,修饰变量不可修改,修饰方法不可重写。

finally则是Java保证重点代码一定要被执行的一种机制。我们可以使用try-finally或者try-catch-finally来进行类似关闭JDBC连接、保证unlock锁等动作。

finalize是基础类Object的一个方法,目的是保证对象在被垃圾收集前完成特定资源的回收。此机制已不推荐使用,在JAVA9被标记为deprecated。

考点分析

这是一个经典的面试题,上面从语法和实践的角度出发,其实还可以从性能、并发、对象生命周期或垃圾收集基本过程等方面深入。

  • 使用final关键字修饰类或者方法,告诉别人这些行为不可更改,保证平台安全;
  • 使用final修饰参数或者变量,可以避免意外赋值导致的错误。可以保护只读数据,在并发编程中,也可以减少同步开销。

对于finally,知道怎么使用即可,需要关闭的连接等资源,推荐使用try-with-resources语句,是Java7提供的。

对于finalize,不推荐使用。因为你不能保证finalize什么时候执行、执行是否符合预期,是否会影响性能,导致程序死锁、挂起等。

知识拓展

有什么机制可以替换finalize吗? Java平台目前在逐步使用java.lang.ref.Cleaner来替换掉原有的finalize实现。

Cleaner的实现利用了幻象引用(PhantomReference),这是一种常 见的所谓post-mortem清理机制。我会在后面的专栏系统介绍Java的各种引用,利用幻象引用和引用队列,我们可以保证对象被彻底销毁前做一些类似资源回收的工作,比如关闭文件描述符(操作系统有限的资源),它比finalize更加轻量、更加可靠。

吸取了finalize里的教训,每个Cleaner的操作都是独立的,它有自己的运行线程,所以可以避免意外死锁等问题。实践中,我们可以为自己的模块构建一个Cleaner,然后实现相应的清理逻辑。下面是JDK自身提供的样例程序:

public class CleaningExample implements AutoCloseable {
    // A cleaner, preferably one shared within a library
    private static final Cleaner cleaner = <cleaner>;
    static class State implements Runnable {
        State(...) {
    // initialize State needed for cleaning action
    }
    public void run() {
        // cleanup action accessing State, executed at most once
    }
    }
    private final State;
    private final Cleaner.Cleanable cleanable
    public CleaningExample() {
        this.state = new State(...);
        this.cleanable = cleaner.register(this, state);
    }
    public void close() {
        cleanable.clean();
    }
}

很多第三方库自己直接利用幻象引用定制资源收集,比如广 泛使用的MySQL JDBC driver之一的mysql-connector-j,就利用了幻象引用机制。幻象引用也可以进行类似链条式依赖关系的动作,比如,进行总量控制的场景,保证只有连接被关闭,相应资源被回收,连接池才能创建新的连接。