对Java中 final、finally、finalize的理解
摘要
极客时间里的Java核心技术系列,第3讲,记录一些笔记。
关键词:copy-on-write,System.exit(1),幻象引用,OOM
final
使用 final 来明确我们代码的语义,或者逻辑意图:
final 修饰的类,不可继承。
final 修饰的方法,不可重写。
final 修饰的变量,不可改变
但需要注意: final 变量 不等于 immutable, 比如:
// final 只能约束 list引用 不能被重新赋值,但是list对象的行为不受影响。
final List<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
// List.of() 方法 创建的是 不可变的list
List<String> unmodifiableList = List.of("list of");
umodifiableList.add("unmodify")
Java目前没有原生的对immutable的支持。如果需要实现 不可变的类,需要做到:
- class 用 final 修饰。
- 成员变量都用 final,private修饰。
- 构造对象用 深拷贝。
- 不实现setter方法。对于getter方法,如果实在想用,需要遵守 copy-on-write 原则。
copy-on-wirte(写时复制) 原则:
是一种程序设计的优化方案,是一种延时懒惰的策略。
很多人共享同一容器,当某人想要修改时,把他复制出去形成新的容器,在新的容器里面修改,改好了再将 原容器的引用 指向 新容器。
finally
finally 是Java中保证重要代码一定要执行的一种机制。
可以用来关闭资源(文件关闭,JDBC连接等等) 或者 unlock锁。
但是 JDK7添加的 try-with-resources 语句 要更好用些。
- 特例:
try{
// do something...
System.exit(1);
}finally{
// 系统退出(exit)了,这个语句不会被执行。。。
// 但是对于系统返回(return)了,是会执行 finally 里的语句的。
System.out.println("execute finally。。。");
}
finalize
finalize 在 JDK9 已经被标记为 deprecated 了。
为什么会 deprecated:
当然是实践证明不好用。。。
一旦实现了 非空finalize 方法,就会导致 对象回收 呈现 数量级上的变慢,约40-50倍的下降。
所以会拖累 垃圾收集器,导致大量对象堆积,容易发生 OutOfMemoryError。
替换成 java.lang.ref.Cleaner 。利用了幻象引用和引用队列,可以保证对象被销毁前 做一些类似 资源回收 的工作。
JDK1.2 开始,对象的引用分为 4 个级别:
- 强引用
好比于 必不可少的生活用品。宁愿发出 OOM 错误,也不愿回收的对象。- 软引用(SoftReference)
好比于 可有可无的生活用品。可以和 引用队列 联用。
垃圾收集器工作了,扫描到它时,内存够就不回收,内存不够就把它回收誊内存出来。- 弱引用(WeakReference)
和 软引用 很像。 可以和 引用队列 联用。
垃圾收集器工作了,扫描到它时,就会把它回收了。- 虚引用(幻象引用) (PhantomReference)
形同虚设,和没有引用差不多。 必须和 引用队列 联用。
参考链接:
http://ifeve.com/java-copy-on-write/
https://juejin.im/post/5bd96bcaf265da396b72f855
https://blog.csdn.net/hnhygkx/article/details/80182906