Q:谈谈final,finally,finalize有什么不同?
final
final可以用来修饰类、方法、变量,分别有不同的意义。final修饰class表示不能扩展继承,final修饰的方法表示不能重写,final修饰的变量表示不可修改。
推荐使用final关键字来明确表明我们代码的语义,明确告知别人,这是不能修改的。
在并发编程中,final声明的变量可以减少额外的同步开销,和省去防御性拷贝的必要。
注意:final不是不可更改的。具体实例如下:
// 此处的final只能约束strList这个引用不能被赋值,
// 但strList对象行为不被final影响,可以添加元素。
final List<String> strList = new ArrayList<>();
strList.add("Hello");
strList.add("World");
// List.of方法创建的是本身不可变的list
List<String> unmodifiableStrList = List.of("hello", "world");
// 此处的add会抛出异常
unmodifiableStrList.add("again");
immutable
如果要实现不可更改的类,有几种方法。
- 将class声明为final
- 将所有的成员变量声明为final和private,并且不设置setter方法。
- 构造对象时,成员变量是使用深度拷贝来初始化,而不是直接赋值,这是一种防御机制,因为你无法确定输入对象不被其他人修改。
finally
finally是保证重点代码一定被执行的一种机制。使用类似于try-catch-finally或try-finally进行关闭JDBC连接、关锁的动作。
对需要关闭连接资源等,更推荐使用Java7中添加的try-with-resources语句。
finalize
finalize是基础类java.lang.Object的一个方法,已经不推荐使用。你无法保证finalize什么时候执行,是否符合预期。使用不当会影响性能,导致程序死锁、挂起。
finalize被设计成对象在垃圾收集前调用,JVM需要对它进行特殊处理。它拖慢了垃圾收集的速度,导致大量对象堆积,有可能会导致OOM。
幻象引用和引用队列
Java平台目前正在逐步用java.lang.ref.cleaner替换掉finalize实现。cleaner的实现利用了幻象引用,这是一种所谓的post-mortem清理机制。利用幻象引用和引用队列,我们可以保证对象被彻底销毁前做一些类似资源回收的工作。
吸取了finalize里的教训,每个cleaner得到操作都是独立的,有自己的运行线程,可以避免意外死锁的问题。
从可预测性的角度看,cleaner或者幻象引用能够改善的程度仍然是有限的。因此,cleaner适合作为最后的保证手段,不能完全依赖它进行资源回收。