java终结疑惑

时间:2012-05-01 04:38:31

标签: java

我对java finalization有一些疑问。 例如,我有一个类FileHelper,这个类与读取文件,写入文件等相关联。 现在我的问题是,我在FileHelper类中有一个方法writeFile()。如果我想关闭该文件 我应该覆盖finalize()方法并关闭文件,还是可以关闭writeFile()方法本身内的文件?哪种方法正确?我已将File变量声明为成员变量。如果覆盖是一个坏主意,那么为什么我们要覆盖finalize()方法呢?哪种情况?我已经阅读了很多文章,他们说要关闭系统资源,如文件,字体等。

4 个答案:

答案 0 :(得分:3)

最佳做法是尽快关闭文件。如果你在FileHelper中有静态方法(假设你的Helper是一堆静态的“帮助”方法)我会关闭里面的文件

static void writeFile(String fileName, String text) { // Exception 
 // Open file here 
 // write text
 // close it
}

覆盖终结的目的是释放非托管资源,例如:文件以防有人忘记这样做。如果有人以这种方式使用你的助手

 FileHelper fileHelper = new FileHelper(file);
 fileHelper.writeFile(text);
 // forgot to fileHelper.close(); 

并且你已经覆盖了finalize并在GC运行时调用close()将关闭文件。问题:

  • 正如我前面提到的那样,文件应该尽快关闭(但不会更快;))
  • 这是不确定的(没有人知道GC什么时候开始)
  • 这应该仅用于防止调用者忘记关闭文件时的情况

答案 1 :(得分:1)

在几乎所有情况下,使用终结器都是一个坏主意。 Java规范声明无法保证终结器的运行。即使他们这样做,你也无法控制何时会发生这种情况。

使用终结器作为主要机制来关闭文件总是一个坏主意。为什么?因为如果GC不运行很长时间,您的应用程序可能会用完文件描述符,文件打开尝试将开始失败。

处理打开的流的最佳方法是将它们保存在局部变量和参数中,并使用try { ...} finally确保它们在完成后始终处于关闭状态。或者在Java 7中,使用新的“try with resource”语法。

如果您需要将流放在成员变量中,您可能应该让父类实现一个关闭流的close()方法,并使用try { ...} finally来确保实例父类关闭。


还应该注意的是,使用终结器来关闭“丢失的”流几乎没有意义。使用需要关闭的外部资源的流类已经有终结器来执行此操作。

答案 2 :(得分:1)

只有在Java垃圾收集器即将回收对象时才会调用finalize()方法。在finalize方法中释放文件句柄是一种不好的做法。

可能会导致java.io.IOException:打开的文件过多,因为无法保证垃圾收集器何时运行。

更好的选择是关闭finally块中的文件读取器/编写器对象。因为它保证运行。

  finally {
  // Always close input and output streams. Doing this closes
  // the channels associated with them as well.
  try {
    if (fin != null)
      fin.close();
    if (fout != null)
      fout.close();
  } catch (IOException e) {
  }}

fin和fout是FileInputStream和FileOutputStream对象。

答案 3 :(得分:0)

覆盖finalize()不是一个好习惯。我会在代码中完成它。