final 是可以用来修饰类、方法、变量、分别不同的意义。
- final 修饰的类class代表不可以继承
- final 修饰的变量表示不可修改
- final 修饰的方法表示不可重写(override)
finall 是Java中保证代码一定要被执行的一种机制,我们可以使用 try-finally 或者 try-catch-finally 来进行类似关闭JDBC,unlock 锁等动作。
finalize 是基础类 java.lang.object 的一个方法,他的设计目的是保证对象在垃圾收集前完成特定资源的回收。finalize机制不推荐使用。JDK9 被标记为 deprecated。
final使用有什么好处?
final 变量产生了某种程序的不可变效果,可以用来保护只读数据。尤其在并发编程中,可以明确地不能赋值 final 变量,有利于减少额外的同步开销。
try{
// do something
System.out.println("do Something");
// system.exit(0):正常退出,程序正常执行结束退出
// system.exit(1):是非正常退出,就是说无论程序正在执行与否,都退出,
System.exit(1);
}finally{
System.out.println("Print from finally");
}
这个比较特殊 上面 finally 里面的代码不会被执行。
如何实现一个不可变类
将class 本身声明为 final ,这样就不能被继承扩展
将所有成员变量定义为 private 和 final ,并且不要实现 setter
通常构造对象是,成员变量使用深度拷贝来初始化,而不是直接赋值。因为你无法确定输入对象不被其他人修改。
如果确实需要实现getter 方法。获知其他可能返回内部状态的方法,使用 copy-on-write (写时复制)原则。Java 有 CopyOnWriteArrayLIst 实现
栗子:
public boolean add(T e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
// 复制出新数组
Object[] newElements = Arrays.copyOf(elements, len + 1);
// 把新元素添加到新数组里
newElements[len] = e;
// 把原数组引用指向新数组
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
final void setArray(Object[] a) {
array = a;
}
为啥说不推荐使用 finalize?
Java 平台正在使用 java.lang.Cleaner 类替换 finalize 实现 ,Cleaner 的实现使用 虚引用(PhantomRefrence),这个是一种常见的所谓 post-mortem 清理机制。
主要原因是 finalize 会掩盖资源回收时的出错信息 看 java.lang.ref.Finalizer 源码
private void runFinalizer(JavaLangAccess jla) {
synchronized (this) {
if (hasBeenFinalized()) return;
remove();
}
try {
Object finalizee = this.get();
if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
jla.invokeFinalize(finalizee);
/* Clear stack slot containing this variable, to decrease
the chances of false retention with a conservative GC */
finalizee = null;
}
} catch (Throwable x) { }
super.clear();
}
Throwable 生吞了一切已成,及时出现异常或者出错,也得不到任何有效信息。
JDK9 平台使用了 Clearner 来替换原来的 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();
}
}
Cleaner 采用 虚引用技术,但是我们平时还是尽量不怎么用,这个只是最后的保障。并不能完全依赖 Cleaner做内存回收。