finalize()方法在三种情况下会被调用 :
1.所有对象被Garbage Collection时自动调用,比如运行System.gc()的时候.
2.程序退出时为每个对象调用一次finalize方法。
3.显式的调用finalize方法
除上述以外,正常情况下,当某个对象被系统收集为无用信息的时候,finalize()方法将被自动调用,但是JVM不保证finalize()一定被调用,所以说 ,finalize()的调用是不确定的。
class Book {
boolean checkOut = false;
Book(boolean checkOut) {
this.checkOut = checkOut;
}
void checkIn() {
checkOut = false;
System.out.println("Checked In!"); //并不影响程序的执行。
}
protected void finalize() {//Java语言允许程序员为任何方法添加finalize( )方法,该方法会在垃圾收集器交换回收对象之前被调用。
if (checkOut) {
System.out.println("Error: checked Out!");
}
}
}
public class Test {
public static void main(String[] args) {
Book novel = new Book(true);
novel.checkIn();//对象 novel调用了checkIn()方法,执行checkOut = false;调用finalize()方法但不符条件。
new Book(true);//匿名对象 调用finalize()方法符合条件,执行方法。当对象被系统收集为无用信息的时候,finalize()方法将被自动调用,但调用是不确定的
//System.gc();//gc 只能清除在堆上分配的内存(纯java语言的所有对象都在堆上使用new分配内存),而不能清除栈上分配的内存
}
}
题外补充:一、gc()与finalize()的区别 :
gc 只能清除在堆上分配的内存(纯java语言的所有对象都在堆上使用new分配内存),而不能清除栈上分配的内存.如果某些对象被分配了栈上的内存区域,对这样的对象进行内存回收就用finalize().
二、finalize()的特点:
1.每一个对象都有一个finalize( )方法,这个方法是从Object类继承来的。 Java语言允许为任何方法添加finalize( )方法,该方法会在垃圾收集器交换回收对象之前被调用。但不要过分依赖该方法对系统资源进行回收和再利用,因为该方法调用后的执行结果是不可预知的。 通过以上对垃圾收集器特点的了解,你应该可以明确垃圾收集器的作用,和垃圾收集器判断一块内存空间是否无用的标准。简单地说,当你为一个对象赋值为null并且重新定向了该对象的引用者,此时该对象就符合垃圾收集器的收集标准。
2.finalize( )方法用来回收内存以外的系统资源,就像是文件处理器和网络连接器。该方法的调用顺序和用来调用该方法的对象的创建顺序是无关的。
3.每个对象只能调用finalize( )方法一次。如果在finalize( )方法执行时产生异常(exception),则该对象仍可以被垃圾收集器收集。
4.垃圾收集器跟踪每一个对象,收集那些不可到达的对象(即该对象没有被程序的任何"活的部分"所调用),回收其占有的内存空间。但在进行垃圾收集的时候,垃圾收集器会调用finalize( )方法,通过让其他对象知道它的存在,而使不可到达的对象再次"复苏"为可到达的对象。既然每个对象只能调用一次finalize( )方法,所以每个对象也只可能"复苏"一次。
5.finalize( )方法可以明确地被调用,但它却不能进行垃圾收集。
6.finalize( )方法可以被重载(overload),但只有具备初始的finalize( )方法特点的方法才可以被垃圾收集器调用。
7.子类的finalize( )方法可以明确地调用父类的finalize( )方法,作为该子类对象的最后一次适当的操作。但Java编译器却不认为这是一次覆盖操作(overriding),所以也不会对其调用进行检查。
8.当finalize( )方法尚未被调用时,System. runFinalization( )方法可以用来调用finalize( )方法,并实现相同的效果,对无用对象进行垃圾收集。
9.当一个方法执行完毕,其中的局部变量就会超出使用范围,此时可以被当作垃圾收集,但以后每当该方法再次被调用时,其中的局部变量便会被重新创建。
10.Java语言使用了一种"标记交换区的垃圾收集算法"。该算法会遍历程序中每一个对象的句柄,为被引用的对象做标记,然后回收尚未做标记的对象。
所谓遍历可以简单地理解为"检查每一个"。 |