我一直在阅读很多关于finalize()的Java新手问题,并发现没有人真正清楚地表明finalize()是一种不可靠的清理资源的方法,这有点令人困惑。我看到有人评论说他们用它来清理连接,这真的很可怕,因为唯一接近于保证连接关闭的方法是最后实现try (catch)。

我没有学过CS,但我已经用Java专业编程近十年了,我从来没有见过有人在生产系统中实现finalize()。这并不意味着它没有用处,或者和我一起工作的人一直在做正确的事情。

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

请提供具体的场景或您的经验,简单地重复Java教科书,或最终确定的预期用途是不够的,因为这不是这个问题的意图。


当前回答

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!

=====================================

所以你可以在finalize方法中使一个不可达的实例可达。

其他回答

删除已经添加到全局/静态位置(不需要)的东西,并在对象被删除时需要删除,这是很方便的。例如:

    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);
        }
    }

您可以将它用作持有外部资源(套接字、文件等)的对象的支持。实现close()方法和需要调用它的文档。

如果检测到close()没有执行,则实现finalize()来执行close()处理。可能会将一些东西转储到stderr,以指出您正在清理有错误的调用者。

它在异常/有bug的情况下提供了额外的安全性。并不是每个调用者每次都会执行正确的try {} finally{}。不幸的是,但在大多数环境中都是如此。

我同意很少有人需要它。正如评论者指出的那样,它带来了GC开销。只有当你在一个长期运行的应用程序中需要“皮带和背带裤”的安全性时才使用。

我看到从Java 9开始,Object.finalize()已弃用!它们将我们指向java.lang.ref.Cleaner和java.lang.ref.PhantomReference作为替代。

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!

=====================================

所以你可以在finalize方法中使一个不可达的实例可达。

自1998年以来,我一直在从事Java专业工作,但我从未实现过finalize()。一次也没有。

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

许多数据库驱动程序在它们的Statement和Connection实现中这样做,以提供一点安全性,防止开发人员忘记调用close。