服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

确保正确的清除


  java不具备象c++的“破坏器”那样的概念。在c++中,一旦破坏(清除)一个对象,就会自动调用破坏器方法。之所以将其省略,大概是由于在java中只需简单地忘记对象,不需强行破坏它们。垃圾收集器会在必要的时候自动回收内存。
  
  垃圾收集器大多数时候都能很好地工作,但在某些情况下,我们的类可能在自己的存在时期采取一些行动,而这些行动要求必须进行明确的清除工作。正如第4章已经指出的那样,我们并不知道垃圾收集器什么时候才会显身,或者说不知它何时会调用。所以一旦希望为一个类清除什么东西,必须写一个特别的方法,明确、专门地来做这件事情。同时,还要让客户程序员知道他们必须调用这个方法。而在所有这一切的后面,就如第9章(违例控制)要详细解释的那样,必须将这样的清除代码置于一个finally从句中,从而防范任何可能出现的违例事件。
  
  下面介绍的是一个计算机辅助设计系统的例子,它能在屏幕上描绘图形:
  
  //: cadsystem.java
  // ensuring proper cleanup
  import java.util.*;
  
  class shape {
   shape(int i) {
    system.out.println("shape constructor");
   }
   void cleanup() {
    system.out.println("shape cleanup");
   }
  }
  
  class circle extends shape {
   circle(int i) {
    super(i);
    system.out.println("drawing a circle");
   }
   void cleanup() {
    system.out.println("erasing a circle");
    super.cleanup();
   }
  }
  
  class triangle extends shape {
   triangle(int i) {
    super(i);
    system.out.println("drawing a triangle");
   }
   void cleanup() {
    system.out.println("erasing a triangle");
    super.cleanup();
   }
  }
  
  class line extends shape {
   private int start, end;
   line(int start, int end) {
    super(start);
    this.start = start;
    this.end = end;
    system.out.println("drawing a line: " +
        start + ", " + end);
   }
   void cleanup() {
    system.out.println("erasing a line: " +
        start + ", " + end);
    super.cleanup();
   }
  }
  
  public class cadsystem extends shape {
   private circle c;
   private triangle t;
   private line[] lines = new line[10];
   cadsystem(int i) {
    super(i + 1);
    for(int j = 0; j < 10; j++)
     lines[j] = new line(j, j*j);
    c = new circle(1);
    t = new triangle(1);
    system.out.println("combined constructor");
   }
   void cleanup() {
    system.out.println("cadsystem.cleanup()");
    t.cleanup();
    c.cleanup();
    for(int i = 0; i < lines.length; i++)
     lines[i].cleanup();
    super.cleanup();
   }
   public static void main(string[] args) {
    cadsystem x = new cadsystem(47);
    try {
     // code and exception handling...
    } finally {
     x.cleanup();
    }
   }
  } ///:~
  
  这个系统中的所有东西都属于某种shape(几何形状)。shape本身是一种object(对象),因为它是从根类明确继承的。每个类都重新定义了shape的cleanup()方法,同时还要用super调用那个方法的基础类版本。尽管对象存在期间调用的所有方法都可负责做一些要求清除的工作,但对于特定的shape类――circle(圆)、triangle(三角形)以及line(直线),它们都拥有自己的构建器,能完成“作图”(draw)任务。每个类都有它们自己的cleanup()方法,用于将非内存的东西恢复回对象存在之前的景象。
  
  在main()中,可看到两个新关键字:try和finally。我们要到第9章才会向大家正式引荐它们。其中,try关键字指出后面跟随的块(由花括号定界)是一个“警戒区”。也就是说,它会受到特别的待遇。其中一种待遇就是:该警戒区后面跟随的finally从句的代码肯定会得以执行――不管try块到底存不存在(通过违例控制技术,try块可有多种不寻常的应用)。在这里,finally从句的意思是“总是为x调用cleanup(),无论会发生什么事情”。这些关键字将在第9章进行全面、完整的解释。
  
  在自己的清除方法中,必须注意对基础类以及成员对象清除方法的调用顺序――假若一个子对象要以另一个为基础。通常,应采取与c++编译器对它的“破坏器”采取的同样的形式:首先完成与类有关的所有特殊工作(可能要求基础类元素仍然可见),然后调用基础类清除方法,就象这儿演示的那样。
  
  许多情况下,清除可能并不是个问题;只需让垃圾收集器尽它的职责即可。但一旦必须由自己明确清除,就必须特别谨慎,并要求周全的考虑。
  
  1. 垃圾收集的顺序
  
  不能指望自己能确切知道何时会开始垃圾收集。垃圾收集器可能永远不会得到调用。即使得到调用,它也可能以自己愿意的任何顺序回收对象。除此以外,java 1.0实现的垃圾收集器机制通常不会调用finalize()方法。除内存的回收以外,其他任何东西都最好不要依赖垃圾收集器进行回收。若想明确地清除什么,请制作自己的清除方法,而且不要依赖finalize()。然而正如以前指出的那样,可强迫java1.1调用所有收尾模块(finalizer)。

扫描关注微信公众号