Java 为什么要实现finalize()?

Java 为什么要实现finalize()?,java,jvm,Java,Jvm,我已经阅读了很多关于finalize()的Java新手问题,发现没有人真正明确指出finalize()是清理资源的不可靠方法,这有点令人困惑。我看到有人评论说他们用它来清理连接,这真的很可怕,因为要保证连接关闭,唯一的办法就是最终实现try(catch) 我没有接受过CS方面的教育,但我已经用Java专业编程近十年了,我从未见过有人在生产系统中实现finalize()。这并不意味着它没有用处,也不意味着与我共事的人做得对 所以我的问题是,对于实现finalize(),有哪些用例不能通过语言中的另

我已经阅读了很多关于
finalize()
的Java新手问题,发现没有人真正明确指出finalize()是清理资源的不可靠方法,这有点令人困惑。我看到有人评论说他们用它来清理连接,这真的很可怕,因为要保证连接关闭,唯一的办法就是最终实现try(catch)

我没有接受过CS方面的教育,但我已经用Java专业编程近十年了,我从未见过有人在生产系统中实现
finalize()
。这并不意味着它没有用处,也不意味着与我共事的人做得对

所以我的问题是,对于实现
finalize()
,有哪些用例不能通过语言中的另一个进程或语法更可靠地处理


请提供具体的场景或您的经验,简单地重复一本Java教科书,或者finalize的预期用途是不够的,这不是这个问题的目的。

我从1998年起就开始专业地使用Java,而且我从未实现过
finalize()
。不是一次。

当编写代码供其他开发人员使用时,需要调用某种“清理”方法来释放资源。有时,其他开发人员忘记调用您的清理(或关闭、或销毁,或其他)方法。为了避免可能的资源泄漏,您可以检查finalize方法以确保该方法已被调用,如果未被调用,您可以自己调用它


许多数据库驱动程序在其语句和连接实现中都这样做,以提供一点安全性,防止开发人员忘记对它们进行关闭调用。

您不应该依赖finalize()来为您清理资源。finalize()在类被垃圾收集之前不会运行,如果是这样的话。使用完资源后,最好显式释放资源。

您可以将其用作保存外部资源(套接字、文件等)的对象的后盾。实现一个
close()
方法并记录需要调用它的文档

执行
finalize()
以执行
close()
处理(如果检测到尚未完成)。可能会有一些东西被转储到stderr,指出你正在清理一个有问题的来电者

它在特殊情况下提供了额外的安全性。并不是每个调用者每次都会做正确的
尝试{}finally{}
操作。不幸的是,在大多数环境中都是如此

我同意很少需要它。正如评论者指出的,它伴随着GC开销。只有在长时间运行的应用程序中需要“安全带和吊带”时才使用


我看到,从Java9开始,它就被弃用了!它们将我们指向并作为替代方案。

我在生产代码中使用finalize的唯一一次是执行检查,确保给定对象的资源已清理,如果未清理,则记录一条非常响亮的消息。它实际上并没有尝试自己去做,如果做得不好,它会大喊大叫。结果证明是非常有用的。

finalize()
中要小心。尤其是在调用close()以确保资源被清理的情况下。我们遇到了几种情况,其中JNI库链接到正在运行的java代码中,在任何使用finalize()调用JNI方法的情况下,我们都会得到非常严重的java堆损坏。损坏不是由底层JNI代码本身造成的,本机库中的所有内存跟踪都很好。事实上,我们是从finalize()调用JNI方法的

这是一个JDK1.5版本,目前仍在广泛使用

直到很久以后,我们才发现出现了问题,但最终罪魁祸首始终是使用JNI调用的finalize()方法。

finalize()
提示JVM在未指定的时间执行代码可能很好。当您希望代码神秘地无法运行时,这是很好的

在终结器中执行任何重要的操作(基本上除了日志记录之外的任何操作)在以下三种情况下也很好:

  • 您希望赌其他最终确定的对象仍将处于程序其余部分认为有效的状态
  • 您希望向所有具有终结器的类的所有方法添加大量检查代码,以确保它们在终结后的行为正确
  • 您希望意外地恢复已完成的对象,并花费大量时间试图找出它们为什么不工作,和/或它们最终发布时为什么没有完成
如果您认为需要finalize(),有时您真正想要的是一个幻影引用(在给出的示例中,它可以保存对其refereand使用的连接的硬引用,并在幻影引用排队后关闭它)。它还有一个特性,它可能神秘地永远不会运行,但至少它不能调用方法或恢复最终确定的对象。因此,它正好适合于您不一定需要干净地关闭该连接,但您非常愿意这样做,并且您的类的客户端不能或不会自己调用close(这其实很公平——如果设计的接口要求在收集之前采取特定的操作,那么使用垃圾收集器有什么意义呢?这让我们回到了malloc/free时代。)

其他时候,你需要你认为你正在管理的资源更加健壮。例如,为什么你需要关闭该连接?它最终必须基于系统提供的某种I/O(套接字、文件等),那么,当最低级别的资源是gced时,为什么你不能依靠系统来关闭它呢?如果
public void finalize() {
  ref1 = null;
  ref2 = null;
  othercrap = null;
}
itsadok@laptop ~/jdk1.6.0_02/src/
$ find . -name "*.java" | xargs grep "void finalize()" | wc -l
41
class MyObject {
    Test main;

    public MyObject(Test t) {    
        main = t; 
    }

    protected void finalize() {
        main.ref = this; // let instance become reachable again
        System.out.println("This is finalize"); //test finalize run only once
    }
}

class Test {
    MyObject ref;

    public static void main(String[] args) {
        Test test = new Test();
        test.ref = new MyObject(test);
        test.ref = null; //MyObject become unreachable,finalize will be invoked
        System.gc(); 
        if (test.ref != null) System.out.println("MyObject still alive!");  
    }
}
This is finalize

MyObject still alive!
@Override
public void finalize()
{
    try {saveCache();} catch (Exception e)  {e.printStackTrace();}
}

public void saveCache() throws FileNotFoundException, IOException
{
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("temp/cache.tmp"));
    out.writeObject(cache);
}
private void addGlobalClickListener() { weakAwtEventListener = new WeakAWTEventListener(this); Toolkit.getDefaultToolkit().addAWTEventListener(weakAwtEventListener, AWTEvent.MOUSE_EVENT_MASK); } @Override protected void finalize() throws Throwable { super.finalize(); if(weakAwtEventListener != null) { Toolkit.getDefaultToolkit().removeAWTEventListener(weakAwtEventListener); } }
public void finalize() throws Throwable {
    super.finalize();
    if (destructiveFinalize) {
        T item;
        for (int i = 0, l = length(); i < l; i++) {
            item = get(i);
            if (item == null) {
                continue;
            }
            if (item instanceof Window) {
                ((Window) get(i)).dispose();
            }
            if (item instanceof CompleteObject) {
                ((CompleteObject) get(i)).finalize();
            }
            set(i, null);
        }
    }
}
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
  // Processing and other logic here.
} catch (Exception e) {
  // log exception
} finally {
  // Just in case we need to do some stuff here.
}