Q1 final、finally、 finalize 有哪些不同
- final 可以用来修饰类、方法、变量,分别有不同的意义。final 修饰的 class 代表不可以继承扩展,final 的变量是不可以修改的,而 final 的方法也是不可以重写的(override)。
- finally 则是 Java 保证重点代码一定要被执行的一种机制。我们可以使用 try-finally 或者 try-catch-finally 来进行类似关闭 JDBC 连接、保证 unlock 锁等动作。
- finalize 是基础类 java.lang.Object 的一个方法,它的设计目的是保证对象在被垃圾收集前完成特定资源的回收。finalize 机制现在已经不推荐使用,并且在 JDK 9 开始被标记为 deprecated。
Q2 final最佳实践:
- 我们可以将方法或者类声明为 final,这样就可以明确告知别人,这些行为是不许修改的。
- 使用 final 修饰参数或者变量,也可以清楚地避免意外赋值导致的编程错误,甚至,有人明确推荐将所有方法参数、本地变量、成员变量声明成 final。
- final 变量产生了某种程度的不可变(immutable)的效果,所以,可以用于保护只读数据,尤其是在并发编程中,因为明确地不能再赋值 final 变量,有利于减少额外的同步开销,也可以省去一些防御性拷贝的必要。
Q3 final需要注意的点
final 不是 immutable,对于对象和列表等需要final数据时,需要特殊处理
1. 将class自身设置为final,防止扩展
2. 将内部属性定义成final或者私有化setter方法
3. 构造变量是采用深拷贝
4. getter采用copyOnWriter原则
CopyOnWrite 容器即写时复制容器,原理就是当我们往一个容器添加元素时,不直接往当前容器添加,而是先将当前容器进行Copy,复制出新的容器,然后往新的容器进行添加元素,添加好之后,再将原来的容器引用指向新的容器。
这样的好处就是,我们可以对CopyOnWrite容器进行并发的读,也不需要加锁,因为当前容器不会添加任何新的元素。
CopyOnWrite容器也是一个读写分离的思想
Q4 finalize的略根性
finalize常常跟GC联系到一起,在GC前被调用,若有耗时逻辑会影响GC效率,可能会导致OOM。
Q5 finalize的替代机制:
Java 平台目前在逐步使用 java.lang.ref.Cleaner 来替换掉原有的 finalize 实现。
Cleaner 的实现利用了幻象引用(PhantomReference),这是一种常见的所谓 post-mortem 清理机制。我会在后面的专栏系统介绍 Java 的各种引用,利用幻象引用和引用队列,我们可以保证对象被彻底销毁前做一些类似资源回收的工作,比如关闭文件描述符(操作系统有限的资源),它比 finalize 更加轻量、更加可靠。
public class CleaningExample implements AutoCloseable {
// A cleaner, preferably one shared within a library
private static final Cleaner cleaner = <cleaner>;
static class State implements Runnable {
State(...) {
// initialize State needed for cleaning action
}
public void run() {
// cleanup action accessing State, executed at most once
}
}
private final State;
private final Cleaner.Cleanable cleanable
public CleaningExample() {
this.state = new State(...);
this.cleanable = cleaner.register(this, state);
}
public void close() {
cleanable.clean();
}
}