0

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

4

4 回答 4

3

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

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

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

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

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

  • 正如我之前提到的,文件应该尽快关闭(但不能更早;))
  • 这是不确定的(没有人知道 GC 何时开始)
  • 这应该仅用于防止调用者忘记关闭文件的情况
于 2012-05-01T04:50:18.983 回答
1

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

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

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

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


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

于 2012-05-01T04:46:34.990 回答
1

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

它可能会导致 java.io.IOException: Too many open files 因为您无法保证垃圾收集器何时运行。

更好的选择是在 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 对象。

于 2012-05-01T04:53:26.823 回答
0

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

于 2012-05-01T04:41:12.233 回答