//: initialization/TerminationCondition.java
// Using finalize() to detect an object that
// hasn't been properly cleaned up.
class Book {
boolean checkedOut = false;
Book(boolean checkOut) {
checkedOut = checkOut;
}
void checkIn() {
checkedOut = false;
}
protected void finalize() {
if(checkedOut)
System.out.println("Error: checked out");
// Normally, you'll also do this:
// super.finalize(); // Call the base-class version
}
}
public class TerminationCondition {
public static void main(String[] args) {
Book novel = new Book(true);
// Proper cleanup:
novel.checkIn();
// Drop the reference, forget to clean up:
new Book(true);
// Force garbage collection & finalization:
System.gc();
}
} /* Output:
Error: checked out
*///:~
说明:这段程序源自《java编程思想》89页
问题1:输出为什么是“Error: checked out”,在哪里调用了finalize()方法,(因为只有finalize()方法里有打印输出语句System.out.println("Error: checked out");)
问题2:书上说,在main()方法里,由于错误,有一本书(即Book对象)为被check in, 要是没有finalize()来验证终结条件,见很难发现这种缺陷,真是怎么回事
问题3:main()方法是不是调用了两次构造方法,第一次“Book novel = new Book(true);”,第二次new Book
问题1:
finalize()方法是object类中的方法,此方法将在对象被销毁的时候调用,被系统认为是垃圾的对象是没有引用的 既 Book b = new Book();当执行b=null;时,该对象没有任何引用指向它,被系统判断为垃圾,垃圾回收机制是系统自己运行的,但也可手动调用既 System.gc()
问题2:
finalize()方法一般用来释放资源,释放被自己所引用的对象,好让垃圾回收器将没用的对象回收,例如打开了一个文件,当此对象将被销毁的时候就一定要判断是否该文件是否被关闭,否则很容易内存溢出,导致程序崩溃
问题3:
确实调用了辆次构造 第一次有引用指向被新构造出来的对象,第二次没有引用指向它,所以调用System.gc()的时候该对象被销毁,销毁前调用了 finalize()方法打印了那句话
system.gc()应该是垃圾回收函数,就是不用的东西就把它收回去,清理出空间来!但是java中的垃圾是自动回收的,它是根据什么来判断要不要把这个变量或对象当作垃圾回收呢?就是根据一个指针,就是说这个变量或对象系统内没有指针指向他了,就是你再想要用这个变量或对象的时候,系统没有办法找到它了,这样就会把他当作垃圾自动回收!就比如说 例子中的 new Book(true);定义的一个无名称的book对象,这个Book 对象他是存在内存里的,但是你能够找到它并且引用它吗?很明显不可以(因为你找不到一个变量指针指向他,所以无法应用呢)。这时候系统就会把它当垃圾回收掉,这就是java 的回收机制!
问题一:
在system.gc()这个调用时,就把你用new Book(true)定义的无名对象给回收了,但是finalize()这个函数要在这个对象“挂掉”之前执行一下!
问题二:
你的问题我也不知道问的是什么,但是根据我的理解
他说的应该是“这个程序调用system.gc的原意是要回收Novel这个book对象的,但是系统的默认回收了却是用new Book(true)定义的无名对象,这样就达不到原来的意图,万一这个对象占用内存很夸张就会导致“头疼的后果”, 所以他建议每个人在写程序的时候最好加finalize()这个函数,确认下到底有没有回收了自己想要回收的东西,从而保证程序的安全性”
问题三:
是调用了两次构造函数,第二次好像不像对吧,它和第一种用法是一样的,只不过是定义了一个没有名字的对象而已
2.在这段程序中第2次new Book(true);未被checkIn,会输出Error: checked out ,如果没有finalize()来验证,你就不知道第2次的new Book(true);未被checkIn,这就是缺陷。
//
因为垃圾回收站只收垃圾。你用Book nextnovel = new Book(true);
创建对象,它被nextnovel所引用,还有用,在引用没有释放它之前,对象当然不能被清理掉,否则gc()就不是回收垃圾了,而是摧毁所有的对象了。
你在Book nextnovel = new Book(true);之后写一句nextnovel = null;
finalize() 就会被调用了,因为对象不被任何reference所引用,自然是垃圾一件。
另外,gc()只能回收本方法内可见的垃圾,本方法内不可见的,自动回收时间不确定。比如你把上面两句放入一个method中:
void doSth(){
Book nextnovel = new Book(true);
nextnovel = null;
}
然后中main中调用doSth(); 再System.gc(); 这时finalize()也不会被调用。
在上面的代码中,new Book(true)肯定就是垃圾,因为它不做任何事情。一般来说,创建对象都要返回给reference,如果象new Book(true);这样直接创建对象而不赋值给任何reference,其目的大致可以分为两种:
1、是为了获得创建对象的“副作用”,这时一般说来对象创建之后就可以扔掉。这个比较简单,不举例了。
2、对象创建后马上把自己注册给了另一个类的静态成员。比如在JDBC中,我们要作的第一件事就是加载Driver类,一般语法如下:
Class.forName("oracle.jdbc.driver.OracleDriver";
也可以这样写:
new oracle.jdbc.driver.OracleDriver();
可以试着在这一句后面加上System.gc(); 你会发现此时gc()没有任何作用,Driver类并不会被清理掉,为什么呢?就是因为它实例化之后就把自己注册给了DriverManager类。
如果你没有用过JDBC,可能对第2点没有什么概念,那么可以看一看下面的例子,单纯的new创建对象之后也不会被回收:
// Tree.java
class Leaf{
static Tree tree;
Leaf(Tree t){
tree = t;
}
}
public class Tree{
int i = 88;
Tree(){
Leaf leaf = new Leaf(this);
}
public void finalize() {
System.out.println("finalize()";
}
public static void main(String[] args){
new Tree();
System.gc();
System.out.println(Leaf.tree.i);
}
}
你可以看到,输出是88而不是finalize()。
如你 所说的 直接调用NEW产生的对象 没有引用 所以直接 给垃圾收集器给 收集了
你改动后 产生的引用 只有当引用 与对象 脱钩时 对象才会给收集
一个例子:
//此类说明了 finalize 关键字以及 System.gc() 的作用
/*
finalize 类似 c++中析构函数,表示对象即将消亡时,调用此方法
gc() 方法表示把拉级回收器启动,把拉圾收走
*/
class Person {
private String name;
private int age;
public Person() {
}
public Person(String name) {
this.name = name;
}
public Person(String name,int age) {
this(name);
this.age = age;
}
//每个类里面都有finalize方法,和构造方法功能相反,一个是对象产生时调用,一个是对象消亡时调用
public void finalize() {
System.out.println("开始清理对象...");
}
public static void main(String[] args) {
//下面三个对象一产生即成为拉圾
new Person();
new Person();
new Person();
//如果不加上下面这句,以上产生的三个对象虽成为拉圾,但不一定马上就会启用拉圾回收机制把拉圾回收走
//所以就可能看不到 finalize 方法内部执行的效果
System.gc();
}
}