finalize是JVM垃圾回收时调用的,基本上垃圾回收的时间是无法保障的,只要JVM发现一个对象无任何引用了,就会去回收它。
system.gc()只是说明代码建议JVM进行垃圾回收。

解决方案 »

  1.   

    /*
    Well,垃圾回收是这样的,它的原理是一种编译器技术,
    称之为“引用计数”技术,也就是说,每个创建的对象,在
    虚拟机的某个地方,保存着对象被引用的数目,如果没有
    引用指向某个对象,那么那个对象就是垃圾。然而JVM不会马上就把那个垃圾回收掉,而要等到JVM发现
    内存不足时,它才会将所有的垃圾回收,这样其实更好,
    频繁的回收垃圾反而会使系统的效率降低。当然你也可以
    显示的调用垃圾回收来回收垃圾(System.gc())。楼主的那个例子编的不好,你给出的第一个程序的执行结果
    也是错的,应该是:
    Begin...Hello!
    Begin...
    Closing...
    Begin...
    Begin...Hello! again.
    Closing...为了更好的理解垃圾回收,下面我附上一个清晰的例子:
    主体还是沿用楼主的代码,不过在fin类中加一个私有的
    整型数据id作为对象的标识,再定义一个静态的整型变量
    count,来统计fin生成的对象数。构造函数只取无参的,
    以下是完整的代码:
    *///t4eleven.java
    class fin 
    {
    int id=0;//记录对象的标识号
    static int count=0;//计数生成的对象数
      
    fin()
    {
    count++;
    setID(count);
    System.out.println("fin类对象 "+id+" 被构造");
    } private void setID(int id)//设置对象的标识号
    {
    this.id=id;
    }
      
    public void finalize()
    {
    System.out.println("fin类对象 "+id+" 被回收");
    }
    }public class t4eleven
    {
    public static void main (String args[])
    {

    fin a = new fin();//对象1被构造,并且被a引用
    new fin();//对象2被构造,但是个匿名对象,只能引用一次,用完就是垃圾
    System.gc();
    //对象2被回收,而对象1则因为有a引用,不看作是垃圾,不回收

    new fin();//对象3被构造,用完一次就没有指向它的引用了,因而就是垃圾
    new fin();//对象4被构造,(同上)
    fin b=new fin();//对象5被构造
    System.gc();
    //对象3和4被回收,而对象5则因为有b引用,不看作是垃圾,不回收
    }
    }/*执行结果:
    ---------
    fin类对象 1 被构造
    fin类对象 2 被构造
    fin类对象 2 被回收
    fin类对象 3 被构造
    fin类对象 4 被构造
    fin类对象 5 被构造
    fin类对象 3 被回收
    fin类对象 4 被回收
    ---------
    */
    /*
    楼主先要清楚一件事情,当你new fin()产生一个对象时,
    它都是一个匿名的对象(编译器内部会给它一个名称)
    而fin a=new fin();做的事情是,先构造一个对象(其实
    也可以理解为是匿名的,然后返回它的地址给a,也就说
    a引用了那个匿名对象),所以严格的讲,a其实并不是对象
    它只是一个对象的引用,只是在JAVA中,为了便于交流
    和理解,一致达成共识,将a看作为是一个fin的对象,然而
    大家心里都要清楚,它其实是一个对象的引用而已。
    */
      

  2.   

    奇怪了,按照楼主的代码,
    第一个程序在我机器上的执行结果是:
    Begin...Hello!
    Begin...
    Closing...
    Begin...
    Begin...Hello! again.
    Closing...第二个程序的执行结果是:
    Begin...Hello!
    Begin...
    Begin...
    Closing...
    Closing...
    Begin...Hello! again.你编译的时候没遇到错???复制你的代码到我的机器发现有编译错误,
    代码没问题,但在最后一个System.gc();后,有两个非法非可显示字符,用HEX查看,
    是A1 A1,删除后,编译成功.执行结果如上.楼主你试试将你现在编译出来的.class删除掉,重新编译运行试试.
    我怀疑你现在用JVM运行的类是你早先编写并编译成功的字节码中的类.
      

  3.   

    JVM用一个系统线程运行finalizer,所以finalizer运行的先后与系统线程调度有关,没有一定之规,贴主可以试试在main()的第一句加上Thread.currentThread().setPriority(Thread.MAX_PRIORITY);,应该能看到closing都被排到最后。
      

  4.   

    “丑石”的考虑,我检查了一下 .class 文件,应该没问题。 至于Al Al,可能是在粘贴的时候弄上去的。因为是在DOS prompt底下粘上去的。按照“宝宝猫”的说法,的确所有closing都到最后了。那是否是说情况会由于jvm的不同,在处理的机制上也存在差异,而导致输出结果的次序不同呢?另外,在System.gc()出现的地方不是应该强制执行garbage collection的吗?那这样finalize()就会被执行,也应该随之输出“Closing...”。如果这样的话,先不考虑线程的优先度,输出结果应该和编程时的预测一样。那会是什么导致不同呢?我的理解不知道对不对。其实我用的是jdk1.2.1,前面说错了,不好意思。
      

  5.   

    “那是否是说情况会由于jvm的不同,在处理的机制上也存在差异,而导致输出结果的次序不同呢?”对“在System.gc()出现的地方不是应该强制执行garbage collection的吗?”不是强制,只是建议JVM进行垃圾收集,JVM完全有权忽略这个建议“其实我用的是jdk1.2.1”估计问题就在这,FutureStonesoft(丑石) 用的可能是1.4