概述
Object的finalize方法定义如下:
protected void finalize() throws Throwable { }
使用protected修饰,所以子类是可以重写该方法的。finalize方法将会在jvm对当前对象进行gc回收的时候调用。
实例
下面的代码简单的演示了finalize方法的使用:
public class FinanizeEscape {
public static void main(String[] args) throws InterruptedException {
System.gc();
Thread.sleep(1000);
}
static class FinalizeObject {
@Override
public void finalize() {
System.out.println("finalize function run..");
}
}
}
这里在调用了System.gc()之后让线程睡了一下,主要是因为即使调用了System.gc(),java虚拟机也不保证一定会执行垃圾回收,同时执行垃圾回收的线程是一个优先级比较低的线程,所以这里等待一下。
运行输出:
finalize function run..
使用finalize“逃逸”垃圾回收
在jvm进行垃圾回收的时候会去判断对象的“是死是活”, 也就是对象是不是可达的,当判断对象是不可达的时候,还没有完全的宣告这个对象的“死亡”,而此时会先做一个判断,判断当前对象是否有必要去执行finalize方法,不需要执行的判断依据是:1)当前对象没有重写finalize方法, 2)当前对象已经调用了finalize方法。而调用finalize方法之后对象则将被回收。这里的调用finalize方法将会成为对象获得“救赎”的最后机会。也就是让别的引用指向当前对象。
例子:
public class FinanizeEscape {
public static void main(String[] args) throws InterruptedException {
FinalizeObject.LAST_STRAW = new FinalizeObject();
//第一次回收
FinalizeObject.LAST_STRAW = null;
System.gc();
Thread.sleep(1000);
System.out.println(FinalizeObject.survived());
//第二次回收
FinalizeObject.LAST_STRAW = null;
System.gc();
Thread.sleep(1000);
System.out.println(FinalizeObject.survived());
}
static class FinalizeObject {
public static FinalizeObject LAST_STRAW = null;
@Override
public void finalize() {
System.out.println("finalize function run..");
LAST_STRAW = this;
}
public static boolean survived() {
return LAST_STRAW != null;
}
}
}
上面的代码使用了一个静态的FinalizeObject的引用LAST_STRAW来作为“救命稻草”,在执行finalize的时候将对象链接到LAST_STRAW引用上。
运行输出:
finalize function run..
true
false
第一次“逃逸”成功,第二次失败。原因是jvm只会调用同一个对象的finalize方法一次。