Java核心 -- final + finally + finalize
final
- 修饰类,代表不可以继承扩展
- 修饰变量,代表变量不可以修改
- 修饰方法,代表方法不可以重写
实践
- 推荐使用
final关键字来明确表示代码的语义和逻辑意图 - 将方法或类声明为
final,明确表示不允许重写或继承 - 使用
final修饰参数或变量,能够避免意外赋值而导致的编程错误 final变量产生了某种程度的不可变(immutable)的效果,可以用于保护只读数据- 现在
JVM足够智能,_**final对性能的影响,在大部分情况下,都没有必要考虑**_,应用程序更应该关注的是语义
final != immutable
Java目前没有原生的immutable支持
1 | // final只能约束strList这个引用不可以被赋值,但strList对象本身的行为是不受影响的 |
immutable类
final class- 所以成员变量定义为
private final,并且不要实现setter方法 - 构造对象时,成员变量使用深度拷贝来初始化
- 防御编程:因为无法确保输入对象不会被其它线程修改
- 如果需要实现
getter,使用copy-on-write原则
finally
- 保证重点代码一定要被执行的一种机制
try-finally和try-catch-finallytry-with-resources(JDK 7引入)
1 | try { |
finalize
java.lang.Object中的一个protected方法- 设计目标:_保证对象在被GC前完成特定资源的回收_
- 不推荐使用,在
JDK 9中已经被标记为@Deprecated(since="9") - 无法保证
finalize()何时会执行,执行的结果是否符合预期- 如果使用不当会影响性能,导致程序死锁、挂起等问题
- 一旦实现类非空的
finalize方法,会导致对象回收呈现数量级上的变慢(40~50倍) - 实现了
finalize方法的对象是特殊公民,JVM需要对它们进行额外的处理finalize本质上成为了快速回收的阻碍者- 可能导致对象经过多个GC周期才能被回收
System.runFinalization()同样是不可预测的- 实践中,
finalize会拖慢GC,导致大量对象堆积,有可能导致OOM - 对于消耗非常高频的资源,不要指望
finalize去承担释放资源的主要职责- 推荐做法:资源用完即显式释放,或者利用资源池来复用
- 另外,
finalize会掩盖资源回收时的出错信息
1 | // Throwable被生吞 |
替代方案 – Cleaner
- Java平台逐渐使用
java.lang.ref.Cleaner替换掉原有的finalize实现 Cleaner的实现利用了幻象引用(Phantom Reference)- 利用幻象引用和引用队列,保证对象被销毁之前做一些类似资源回收的工作
Cleaner比finalize更加轻量,更加可靠- 每个
Cleaner的操作都是独立的,都有自己的运行线程,可以避免意外死锁等问题 - 从可预测的角度来判断,
Cleaner或者幻象引用改善的程度依然是有限的- 由于种种原因导致幻象引用堆积,同样会出现问题
Cleaner适合作为最后的保证手段,而不能完全依赖Cleaner进行资源回收
1 | public class CleaningExample implements AutoCloseable { |
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.











