Java有析构函数吗?我好像找不到任何关于这个的文件。如果没有,我怎样才能达到同样的效果?

为了使我的问题更具体,我正在编写一个处理数据的应用程序,规范说应该有一个“重置”按钮,使应用程序恢复到最初的启动状态。但是,除非应用程序关闭或按下重置按钮,否则所有数据必须是“活的”。

作为一个通常的C/ c++程序员,我认为这是微不足道的实现。(因此我打算最后实现它。)我构造了我的程序,使所有“可重置”的对象都在同一个类中,这样当按下重置按钮时,我就可以销毁所有“活动”对象。

我在想,如果我所做的只是解除对数据的引用,并等待垃圾收集器收集它们,如果我的用户重复输入数据并按下重置按钮,是否会出现内存泄漏?我还在想,既然Java作为一种语言相当成熟,应该有一种方法来防止这种情况发生或优雅地解决这个问题。


当前回答

不,这里没有析构函数。原因是所有Java对象都是堆分配和垃圾收集。没有显式的释放(即c++的delete操作符),就没有实现真正析构函数的合理方法。

Java does support finalizers, but they are meant to be used only as a safeguard for objects holding a handle to native resources like sockets, file handles, window handles, etc. When the garbage collector collects an object without a finalizer it simply marks the memory region as free and that's it. When the object has a finalizer, it's first copied into a temporary location (remember, we're garbage collecting here), then it's enqueued into a waiting-to-be-finalized queue and then a Finalizer thread polls the queue with very low priority and runs the finalizer.

当应用程序退出时,JVM停止而不等待挂起的对象完成,因此实际上不能保证终结器将运行。

其他回答

在Java中,最接近析构函数的是finalize()方法。与传统析构函数的最大区别在于,您不能确定何时调用它,因为这是垃圾收集器的职责。我强烈建议在使用它之前仔细阅读它,因为用于文件句柄等的典型RAIA模式不能可靠地使用finalize()。

随着Java 1.7的发布,现在有了使用try-with-resources块的额外选项。例如,

public class Closeable implements AutoCloseable {
    @Override
    public void close() {
        System.out.println("closing..."); 
    }
    public static void main(String[] args) {
        try (Closeable c = new Closeable()) {
            System.out.println("trying..."); 
            throw new Exception("throwing..."); 
        }
        catch (Exception e) {
            System.out.println("catching..."); 
        }
        finally {
            System.out.println("finalizing..."); 
        } 
    }
}

如果执行这个类,则在try块剩余时,在catch块和finally块执行之前,将执行c.close()。与finalize()方法不同,close()保证被执行。但是,不需要在finally子句中显式地执行它。

因为Java是一种垃圾收集语言,所以您无法预测对象何时(甚至是否)会被销毁。因此没有直接等价的析构函数。

有一个被称为finalize的继承方法,但它完全由垃圾回收器自行调用。因此,对于需要显式清理的类,约定是定义一个close方法,并仅使用finalize方法进行完整性检查(即,如果close未被调用,则立即执行并记录错误)。

最近有一个问题引发了关于finalize的深入讨论,所以如果需要的话,应该会提供更多的深度……

如果你有机会使用上下文和依赖注入(CDI)框架,比如Weld,你可以使用Java注释@Predestroy来做清理工作等。

@javax.enterprise.context.ApplicationScoped
public class Foo {

  @javax.annotation.PreDestroy
  public void cleanup() {
    // do your cleanup    
  }
}

在Java中,垃圾收集器自动删除未使用的对象以释放内存。所以Java没有析构函数是很合理的。