回答
- final 可以用来修饰类、方法、变量,final修饰的 class 代表不可以继承扩展,final 的变量是不可以修改的,而final的方法是不可以重写的(override);
- finally 是 Java 保证重点代码一定要被执行的一种机制。我们可以使用 try-finally 或者 try-catch-finally 来进行类似关闭JDBC连接、保证 unlock 锁等动作。
- finalize 是基础类 java.lang.Object 的一个方法,它的设计目的是保证对象在被垃圾收集前完成特定资源的回收。finalize 机制现在已经不推荐使用了,并且在JDK9开始被标记为 deprecated。
关于用 final 关键字来提升性能:在日常开发中,除非有特别考虑,不然最好不要指望这种小技巧带来的所谓性能好处,程序最好是体现它的语义目的。
对于finally,知道怎么用就足够了,需要关闭连接等资源时,更推荐使用 Java 7 中添加的 try-witch-resources 语句,因为通常Java 平台能够更好地处理异常情况,编码量也少很多。
对于 finalize,明确不推荐使用它。你无法保证 finalize 什么时候执行,执行的是否符合预期,使用不当会影响性能,导致程序死锁、挂起等。
知识扩展
- final 不等同于 immutable
final 只能约束 strList 这个引用不可被赋值,但 strList 对象行为不被final 影响,添加元素等操作是完全正常的。如果我们真的希望对象本身是不可变的,需要相应的类支持不可变的行为。List.of 方法创建的是不可变的List,最后那句 add 会在运行时抛出异常。final List<String> strList = new ArrayList<>();
strList.add("Hello");
strList.add("world");
List<String> unmodifiableStrList = List.of("hello", "world");
unmodifiableStrList.add("again");
如果要实现 immutable 的类,我们要做到:
- 将 class 自身声明为 final,这样别人就不能扩展来绕过限制了;
- 将所有成员变量定义为 private 和 final,并且不要实现 setter 方法;
- 构造对象时,成员变量使用深度拷贝来初始化,而不是直接赋值,这是一种防御措施,因为你无法确定输入对象不被其他人修改;
- 如果确实需要实现 getter 方法,或者其他可能会返回内部状态的方法,使用 copy-on-write原则,创建私有的copy;
- finalize 真的那么不堪?
finalize 的执行是和垃圾收集关联在一起的,一旦实现了非空的 finalize 方法,就会导致相应对象回收呈现数量级上的变慢。
因为 finalize 被设计成在对象被垃圾收集前调用,这就意味着实现了 finalize 方法的对象是个 “特殊公民”,JVM 要对它进行额外处理。finalize 本质上成为了快速回收的阻碍者,可能导致你的对象经过多个垃圾收集周期才能被回收。
在实践中,因为 finalize 拖慢垃圾收集,导致大量对象堆积,也是一种典型的导致 OOM 的原因。
从另一个角度,我们要确保回收资源就是因为资源都是有限的,垃圾收集时间的不可预测,可能会极大加剧资源占用。这意味着对于消耗非常高频的资源,千万不要指望 finalize 去承担资源释放的主要职责,最多让 finalize 作为最后的 “守门员”, 况且,它已经暴露了如此多的问题。所以,资源用完即显式释放,或者利用资源池来尽量重用。
finalize 还会掩盖资源回收时的出错信息。
- 有什么机制可以替换 finalize 吗?
Java 平台正逐步用 java.lang.ref.Cleaner 来替换原有的 finalize 实现。Cleaner 的实现利用了幻象引用(PhantomReference),这是一种常见的 post-mortem清理机制。利用幻象引用和引用队列,我们可保证对象被彻底销毁前做一些类似资源回收的工作,比如关闭文件描述符(操作系统有限的资源),它比finalize 更加轻量、更加可靠。
每个Cleaner 的操作都是独立的,它有自己的运行线程,所以可以避免意外死锁等问题。
Cleaner 或者幻象引用改善的程度仍然是有限的,如果由于种种原因导致幻想引用堆积,同样会出现问题。所以,Cleaner 适合作为一种最后的保证手段,而不是完全依赖 Cleaner 进行资源回收。
其他
列几个 fianlly 不会被执行的情况:
- try-cach 异常退出 ```java try{ system.exit(1) }finally{ print(abc) }
2. 无限循环
```java
try{
while(ture){
print(abc)
}
}finally{
print(abc)
}
- 线程被杀死
当执行 try,finally 的线程被杀死时。finally 也无法执行。
总结
1,不要在 finally 中使用 return 语句。
2,finally 总是执行,除非程序或者线程被中断。