Java核心技术36讲--final、finally、finalize比较

在Java语言中,有很多关键字非常类似,但是用途却相差很大,因此,有必要对其进行识别,理清其用法

final

final可以用来修饰类、方法、变量,对于被final修饰的class来说,其代表该类不可以被继承扩展,而final修饰的变量则是不可以修改的, 对于被final修饰的方法来说,意味着该方法将是不可以被重写的(override) 。可以将方法或者类声明为final,这样就可以明确告知别人,这些行为是不许修改的。

在Java核心类库及一些框架的源码中,可以发现相当一部分的类都被声明为final class,这样做可以有效避免API 使用者更改基础功能,某种程度上,这是保证平台安全的必要手段。 其主要好处有以下两点

  • 使用final修饰参数或者变量,可以有效地避免意外赋值导致的编程错误

  • final变量产生了某种程度的不可变(immutable)的效果,所以,可以用于保护只读数据,尤其是在并发编程中,因为明确地不能再赋值 final 变量,有利于减少额外的同步开销,也可以省去一些防御性拷贝的必要

    需要注意的是,final并不等同于immutable

    来看下面一段代码

    1
    2
    3
    4
    5
    final List<String> strList = new ArrayList<>();
    strList.add("Hello");
    strList.add("world");
    List<String> unmodifiableStrList = List.of("hello", "world");
    unmodifiableStrList.add("again");

    final只能约束strList这个引用不可以被赋值,但是strList对象行为不被final影响,添加元素等操作是完全正常的。如果希望对象本身是不可变的,那么需要相应的类支持不可变的行为。在上面这个例子中,JDK 9提供的List.of方法创建的是不可变List,最后那句add会在运行时抛出异常。

finally

finally是Java保证重点代码一定要被执行的一种机制。可以使用try-finally或者try-catch-finally来进行类似关闭JDBC连接等释放资源的操作

fnalize

finalize是基础类java.lang.Object 的一个方法,它的设计目的是保证对象在被垃圾收集前完成特定资源的回收。finalize机制现在已经不推荐使用,并且在JDK 9开始被标记为deprecated。如果没有特别的原因,不要实现finalize方法,也不要指望利用它来进行资源回收。其原因有

  • 因为,finalize被设计成在对象被垃圾收集前调用,这就意味着实现了finalize方法的对象是个“特殊公民”,JVM要对它进行额外处理。finalize本质上成为了快速回收的阻碍者,可能导致你的对象经过多个垃圾收集周期才能被回收。正是由于finalize的执行是和垃圾收集关联在一起的,一旦实现了非空的finalize方法,就会导致相应对象回收呈现数量级上的变慢
  • 要确保回收资源就是因为资源都是有限的,垃圾收集时间的不可预测,可能会极大加剧资源占用。这意味着对于消耗非常高频的资源,千万不要指望finalize去承担资源释放的主要职责