final、finally、finalize

final

概述

final可以用来修饰类、方法、变量。

final类

final修饰的类不可以被继承。

final方法

final修饰的方法是不可以被重写的。

final变量

final修饰的变量是不可以被修改的。

注意,final并不是immutable。如果final修饰的变量是一个对象,final只能保证这个变量的对象引用不会改变,但对象本身是可以被修改的。

final List<String> strList = new ArrayList<>();
strList.add("Hello");
strList.add("world");
1
2
3

immutable类的实现

  • 将class自身声明为final,防止别人通过继承扩展来绕过限制。

  • 将所有成员变量定义为private final,并且不要实现setter方法。

  • 构造对象时,成员变量使用深度拷贝来初始化,而不是直接赋值。这是一种防御措施,因为你无法确定输入对象不被其他人修改。

  • 如果需要实现getter方法,或者其他可能返回内部状态的方法,使用copy-on-write原则,创建一份副本返回。

finally

概述

finally是Java保证重点代码一定要被执行的一种机制。

在实际开发中,常使用try-finallytry-catch-finally来进行类似关闭JDBC连接、保证unlock等动作。

try-with-resources

其实,如果是关闭实现了CloseableAutoCloseable接口的资源,推荐使用JDK7新增的try-with-resources来完成,避免书写冗余代码。

不会被执行的finally

注意,下面的finally中的代码不会被执行。

try {
    // 业务处理
    System.exit(1);
} finally {
    System.out.println("Print from finally");
}
1
2
3
4
5
6

finally与return

如果try语句中有return,会先将返回值保存在一个局部变量中,再执行finally语句,最后返回之前保存的局部变量。

int testReturnInTryClause() {
    int x = 1;
    try {
        return ++x;
    } finally {
        ++x;
    }
}

int y = testReturnInTryClause() // 2
1
2
3
4
5
6
7
8
9
10

finalize

概述

finalize是基础类java.lang.Object的一个方法。

它的设计目的是保证对象在被垃圾收集前完成特定资源的回收。

finalize的原理

垃圾收集器在回收一个对象前,会先判断此对象是否有必要执行finalize():该对象的finalize()被重写,而且JVM之前没有执行过它的finalize()

若被回收对象的finalize()需要被执行,那么它就会被放置在一个叫做F-Queue的队列中,稍后JVM的Finalizer线程会执行这个队列中的各个对象的finalize()。而这个对象会在下一次垃圾收集时才会被回收。

finalize的缺点

从垃圾回收的角度来看:

  • finalize被设计成在对象被垃圾收集前调用,JVM要对它进行额外处理。

  • 因此,finalize成为了快速垃圾回收的阻碍者,它会拖慢了垃圾收集,可能会导致大量“无用”对象的堆积,最终也许会导致OOM。

从资源回收的角度来看:

  • 资源是有限的,而垃圾收集的时间是不可预测的,如果依靠finalize去释放资源,可能会极大加剧资源的占用。

  • 应该使用finally等机制实现“资源用完即释放”,最多让finalize作为保底的措施。

  • finalize还会掩盖资源回收时的出错信息,生吞异常。

finalize机制现在已经不推荐使用,并且在JDK9开始被标记为deprecated。