我在看java编程思想有个地方不太明白代码如下:
public class Book {
  boolean checkedOut = false;
  public Book(boolean checkedOut) {
    this.checkedOut = checkedOut;
  }  public void checkedIn() {
    checkedOut = false;
  }  public void finalize() {
    if (checkedOut) {
      System.out.println("ERROR: checked out");
    }
  }  public static void main(String[] args) {
    Book b = new Book(true);  
    new Book(true);
    System.gc();
  }
}执行后显示:
ERROR: checked out
因为new Book(true);(不是Book b = new Book(true);而是下面这行)被回收,调用了finalize函数而显示的如果我改成:
  public static void main(String[] args) {
    Book b = new Book(true);
    b = null;
    System.gc();
  }
同样的道理,b=null而垃圾回收器要回收Book b = new Book(true);这行生成的对象但是我改成:
  public static void main(String[] args) {
    if (true) {
      Book b = new Book(true);
    }
    System.gc();
  }
却不显示了,就是说没有回收,按道理来说b在if以内才有效,除了if的大括号应该就是垃圾了亚。在调用System.gc();的时候,也应该回收Book b = new Book(true);这样所产生的对象呀?但是为什么没有?

解决方案 »

  1.   

    java的垃圾回收机制 其实并不是说你调用了gc就一定会执行,总的来说gc是有jvm来负责调用的,当你的对象不存在任何引用的时候,gc才会回收垃圾对象,而你这里虽然在if中new了一个对象b,因此而存在引用关系,即便你后边主动调用gc,但jvm并不会执行的。
      

  2.   

    bmw219(bmw219):
    如果我改成:
      public static void main(String[] args) {
        if(true) {
          Book b = new Book(true);
        }
        Book c = new Book(true);
        c = null;
        System.gc();
      }
    }
    则显示:
    ERROR: checked out
    ERROR: checked out就是说回收了Book b = new Book(true);和Book c = new Book(true);产生的对象如果我这样:
      public static void main(String[] args) {
        if (true) {
          Book b = new Book(true);
        }
        new Book(true);
        System.gc();
      }
    }
    则显示:
    ERROR: checked out,就是说只回收了new Book(true);产生的对象
    按照你说的:当你的对象不存在任何引用的时候,gc才会回收垃圾对象。为什么第一个对b进行了回收,说明b不存在应用了(可以看成b=null吧?),但是第二个例子为什么不对b进行回收呢?
      

  3.   

    看争端出现在Book b = new Book(true);  
        new Book(true);这两句代码中。垃圾回收器system.gc()是在一块内存没被引用的这种条件下做回收的。从上面两句代码看出"b"指针指向new Book(true)这块地址,说明new Book(true)在被引用中。后面句“new Book(true)”没有被任何指针引用,那么它就属于一块垃圾,垃圾车(system.gc)来后,一下子就被清理了。
      

  4.   

    lllllllllluoyi(罗毅)  if (true) {
          Book b = new Book(true);
        }但是这样的b.在{}外面就是没有用的了,但是b的指针还是指向new Book(true);这块地址,虽然程序不用了,但是jvm没有给它看做垃圾,还是什么?总之它没有回收亚
      

  5.   

    这个东西真的有点怪,要改成下面这种情况,它还是会回收的。
      public static void main(String[] args) {
        for(int i=1;i<2;i++)
        {
    Book b = new Book(true);
    }
        System.gc();
      }
      

  6.   

    垃圾回收器system.gc()是在一块内存没被引用的这种条件下做回收的。
    针对LZ的发言,if (true) {
          Book b = new Book(true);
        }
    b指针是已经存在的,虽然b在程序中没有使用,但b指定的地址new Book(true)也不是垃圾,因为b指向new Book(true),它们的关系没有断开.就像有美女拎着一塑料袋,她仍到垃圾箱时,这时美女跟塑料袋脱离了关系,袋子没有了价值,现在袋子就是垃圾,当她把袋子作为装零食的容口或者放在衣袋里,那么袋子跟美女还存在的关系。
    所以在这里b没有把new Book(true)甩掉,所以垃圾车不用去扫垃圾。现在针对"lgh2008(ar_guang)"的发言进行解析!
    public static void main(String[] args) {
        for(int i=1;i<2;i++)
        {
    Book b = new Book(true);
    }
        System.gc();
      }
    一看这段代码就会产生垃圾,在这个循环中Book b实例变量的作用范围只存在于这个循环体内,每次循环,都要建立一个new Book(true)对象,它都在循环结束时,这个实例变量将在堆栈移除,这时实例变量对应的内存地址没有指针引用,所以成一块垃圾内存,如果改为for(int i=1;i<6;i++),那么将产生6块垃圾地址。LZ: public static void main(String[] args) {
        Book b = new Book(true);
        b = null;
        System.gc();
      }
    同样的道理,b=null而垃圾回收器要回收Book b = new Book(true);这行生成的对象
    -------------------------------
    这里也是一样的道理,首先创建了Book对象,b指向new Book(true)地址,后面句b = null的意思是b断开了与任何对象的联系。所以前面建立的对象new Book(true)将被孤独,成为垃圾内存地址,如果new Book(true)没有被释放,那么破坏者可以通过这块内存进行攻击。
      

  7.   

    lllllllllluoyi(罗毅)
    谢谢你,我懂了
    但是这样写得话
    if (true) {
          Book b = new Book(true);
        }
    虽然在程序中b看成了垃圾,但是在jvm中没有看成垃圾,如果像这样的情况在程序中的很多的话,是不是他们都不能被释放。对吗?如果是,那么一般来说,最好是这样写:
    if (true) {
          Book b = new Book(true);
          b= null;
        }
    对吗?这样的话。在gc的时候就可以释放内存了,不知道我这样理解对不?
      

  8.   

    lllllllllluoyi(罗毅) 
    我有个问题还是没太搞清楚,请解释下:
    class  Book
    {
         boolean  checkedout = false ;
         Book(boolean checkedout)
         {
            this.checkedout=checkedout;
         }
         void checkin()
         {
             checkedout=false;
         }
         public void finalize()
         {
             if(checkedout)
             {
                 System.out.println("Error: checkedout");
             }
         }
      

     public class finalize
    {
         public static void main(String[] args) {
                      if (true) {
                           Book b = new Book(true);
                         
                      }
                      Book c = new Book(true);
                      c = null;
        
                     System.gc();
      }}
    怎么打印结果是两个:Error: checkedout呢
    不是说b和那个对象还有联系吗
      

  9.   

    打印两个的原因:
    1、Book b = new Book(true)是建立在if代码体内的,那么它的作用范围只存在于if的范围内,也就是说在if范围外是不能调用b实例变量的。当if结束后实例变量b已经在堆栈被移除,那么new Book(true)内存地址就被孤立起来,成为垃圾。
    2、Book c = new Book(true);
                      c = null;
      这句代码我上面也说过的"首先创建了Book对象,c指向new Book(true)地址,后面句c = null的意思是c断开了与任何对象的联系。所以前面建立的对象new Book(true)将被孤独,成为垃圾内存地址,如果new Book(true)没有被释放,那么破坏者可以通过这块内存进行攻击。"
      

  10.   

    lllllllllluoyi(罗毅) 
    我看到你的回答又糊涂了:
    你说的:
    Book b = new Book(true)是建立在if代码体内的,那么它的作用范围只存在于if的范围内,也就是说在if范围外是不能调用b实例变量的。当if结束后实例变量b已经在堆栈被移除,那么new Book(true)内存地址就被孤立起来,成为垃圾。
    但是这样:
      public static void main(String[] args) {
        if (true) {
          Book b = new Book(true);
        }
        System.gc();
      }
    按照你的解释:当if结束后实例变量b已经在堆栈被移除,那么new Book(true)内存地址就被孤立起来,成为垃圾。
    但是这样怎么没有回收呢?
      

  11.   

    System.gc()只不是把对象置一个回收标志,表示它优先会被回收,并不等于实时回收,至于它什么时候回收就要看JVM的内部机制了
      

  12.   

    高手们:我刚刚学java,也是在看编程思想也是刚刚看到这个地方,我觉着这个帖子发得真的是太好了!感谢楼主啊!不过我才识学浅有个地方不太明白,希望高手指教。在原程序就是最上面那个帖子里,为什么执行后,会显示“Error: checked out ”呢,创建的对象没有调用finalize()这个方法阿?
      

  13.   

    wangx1949() 
    如果我是这样  
    public static void main(String[] args) {
        if(true) {
          Book b = new Book(true);
        }
        Book c = new Book(true);
        c = null;
        System.gc();
      }
    }
    显示了两个:Error: checkedout 说明垃圾回收器动作了的,但是如果我这样
      public static void main(String[] args) {
        if (true) {
          Book b = new Book(true);
        }
        System.gc();
      }
    按照lllllllllluoyi(罗毅) 说的new Book(true);产生的对象也是垃圾。为什么回收器没有动作呢?如果说是回收器在内存不够的时候动作,为什么第一个就回收了呢?
    这里我还是没有懂。
    如果说:System.gc()只不是把对象置一个回收标志,表示它优先会被回收,并不等于实时回收,至于它什么时候回收就要看JVM的内部机制了。那为什么第一种情况就可以及时被回收,但是第二种情况却不能呢?
      

  14.   

    Turingwang(图灵王) 
    请详细看书,书上有很详细地说明
      

  15.   

    垃圾回收的关键不是你主动,而是jvm自动或被动(当内存资源不足的时候)去gc因此你代码的改动并不能说明,对象存在引用或者是什么其他的原因导致。
      

  16.   

    所以 回收时 出现不同结果 很正常 System.gc()只是通知 不是 命令
      

  17.   

    public static void main(String[] args) {
        if(true) {
          Book b = new Book(true);
        }
        Book c = new Book(true); //在这个地方jvm会检查有没有垃圾
        c = null;  //再次检查
        System.gc();
      }
    }
    显示了两个:Error: checkedout 说明垃圾回收器动作了的,但是如果我这样
      public static void main(String[] args) {
        if (true) {
          Book b = new Book(true);
        }   //虽然b的作用于在if里,但是由于后面没有创建新的对象,所以jvm就不检查了。
        System.gc(); //可以看出垃圾回收机制完全是被动性的,你new第二次该对象的时候她才
                     //会检查你上一个引用是否还有用。
      }推理可得:下面这段代码将只打印一个 ERROR:...
    public static void main(String[] args) {
        if(true) {
          Book b = new Book(true);
        }
        Book c = new Book(true); 
        System.gc();
      }
    }
      

  18.   

    public static void main(String[] args) {
                      for(int i = 0; i < 1; i++) {
                       Book b = new Book(true);
                      }
                   
        
                     System.gc();
      }
    这个离开scope也是只生成一个对象啊,
    却要打印出来
    奇怪这又如何解释呢
      

  19.   

    zorro09(啊!上帝!) 有道理!