在 Java 中清理对象的最佳方法是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1380640/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 11:23:29  来源:igfitidea点击:

What is the best way to clean up an Object in Java?

java

提问by pankajt

We don't have any destructor in Java as we have in C++.

我们在 Java 中没有像在 C++ 中那样的任何析构函数。

Q1.How should we clean up any Object in java.

一季度。我们应该如何清理java中的任何对象。

Q2.Is there any alternative to a finally block.

Q2。有没有finally块的替代方法。

Q3.Sometimes we have to call explicitely initialization/termination of a third party code from our class e.g.

Q3。有时我们必须从我们的类中明确调用第三方代码的初始化/终止,例如

public classs MyClass{
    public MyClass(){
        ThirdPartyInitialize();
    }

    protected void finalize(){
        ThirdPartyTerminate();
    }
}

Is this the correct way?

这是正确的方法吗?

采纳答案by SingleShot

You generally cannot "clean up" Java objects yourself. The garbage collector decides when to clean objects up. You can indicate when you are done with an object reference by setting it to null, but generally just letting it go out of scope is good enough. Either way, you still have no control over when it gets garbage collected.

您通常无法自己“清理”Java 对象。垃圾收集器决定何时清理对象。您可以通过将对象引用设置为 来指示何时完成了对象引用null,但通常只是让它超出范围就足够了。无论哪种方式,您仍然无法控制它何时被垃圾收集。

The finallyblock is intended for performing actions whether an exception is thrown from a tryblock or not, and is the best place to perform clean up. Generally you only would clean up non-object resources like open streams.

finally无论是否从try块中抛出异常,该块都用于执行操作,并且是执行清理的最佳位置。通常,您只会清理非对象资源,例如开放流。

finalize()is not guaranteed to be called because the garbage collector is not guaranteed to be called before your program exits. It is not really like a C++ destructor because C++ destructors are always called and you can rely on them being called. You cannot rely on finalize()being called.

finalize()不能保证被调用,因为垃圾收集器不能保证在你的程序退出之前被调用。它不像 C++ 析构函数,因为 C++ 析构函数总是被调用,你可以依赖它们被调用。你不能依赖finalize()被召唤。

So 1) use finallyblocks to release non-object resources 2) let the garbage collector clean up object-resources 3) you can hint to the garbage collector that you are done with an object by setting it to nullif it is used in a long-running method.

所以 1) 使用finally块来释放非对象资源 2) 让垃圾收集器清理对象资源 3) 你可以通过设置它来提示垃圾收集器你已经完成了对对象的处理,null如果它被长期使用 -运行方法。

回答by James Black

The finalize is used similar to a destructor, but, if you use the try...finally block for resources then you can open a resource and in the finally block you close the resource.

finalize 的使用类似于析构函数,但是,如果您对资源使用 try...finally 块,那么您可以打开一个资源,并在 finally 块中关闭该资源。

The finally block is always called, when the block is exited, either normally or through an exception being thrown.

finally 块总是在块退出时被调用,正常情况下或通过抛出异常。

Finalize is risky for resource management, as you don't know when it will be called, and if it closes an object that also has finalize then it can take a while.

Finalize 对资源管理来说是有风险的,因为你不知道它什么时候会被调用,如果它关闭了一个也有 finalize 的对象,那么它可能需要一段时间。

The finally block is the better approach.

finally 块是更好的方法。

回答by dave4351

You could also add a shutdown hookto your program, if your program is shutting down too:

如果您的程序也正在关闭,您还可以为您的程序添加一个关闭钩子

//add shutdown hook
Runtime.getRuntime().addShutdownHook(new Thread() {
    public void run() {
        ThirdPartyTerminate();
    }
});

回答by Tom Hawtin - tackline

The best way to clean up after objects is to just drop the object.

清理对象后的最佳方法是直接放下对象。

Finally blocks can be abstracted using the Execute Around idiom.

finally 块可以使用 Execute Around 习惯用法进行抽象。

Finalisers should be avoided. They probably wont get called immediately. The clean up should happen anyway. They are relatively slow. You might want to add one as a safety-net if you are writing a low-level resource wrapper (for, say, a file handle) if performance is not critical.

应避免终结器。他们可能不会立即接到电话。无论如何都应该进行清理。它们相对较慢。如果您正在编写低级资源包装器(例如,文件句柄),并且性能不重要,您可能希望添加一个作为安全网。

回答by cafebabe

Here'sa good insight about finalizers.

这里有一个关于终结器的很好的见解。

回答by Vineet Reynolds

You can clean up objects by removing references to it, when you no longer need it. You dont have to do it explicitly. An explicit cleanup would require setting the reference to null, thereby providing a hint to the garbage collector that the object can be collected. This hint works because of internal reference counts for each object, that are maintained internally. For instance

当您不再需要它时,您可以通过删除对它的引用来清理对象。您不必明确地执行此操作。显式清理需要将引用设置为 null,从而向垃圾收集器提供可以收集对象的提示。这个提示之所以有效,是因为每个对象的内部引用计数都是在内部维护的。例如


C a = new C(); //create an object of class C and assign it to 'a'
a = new C(); //create another object of class C and assign it to 'a'. The older object is no longer referred to. It is now eligible for GC.

There are better alternatives to finalize() depending on how much finalize() is helping your situation.

finalize() 有更好的替代方案,具体取决于 finalize() 对您的情况有多大帮助。

Often, the best practice is to provide a method like close() or disposeResources() in the API which will allow the caller to help the API clean up itself. For instance, the java.sql.Connection class does this. This is better than the finalize() method, since the JVM will call the finalize() method. Often the finalize() method will be run by a low priority thread in the JVM, leading to certain strange errors.

通常,最佳实践是在 API 中提供类似 close() 或 disposeResources() 的方法,这将允许调用者帮助 API 自行清理。例如,java.sql.Connection 类就是这样做的。这比 finalize() 方法更好,因为 JVM 将调用 finalize() 方法。finalize() 方法通常会由 JVM 中的低优先级线程运行,从而导致某些奇怪的错误。

In the case of the Connection class, waiting for the JVM to perform finalization does prove costly in a lot of applications, since a database can accept only so many connections at a time. Therefore, most programmers will call close() explicitly on a Connection object.

在 Connection 类的情况下,等待 JVM 执行终结在许多应用程序中被证明是昂贵的,因为数据库一次只能接受这么多连接。因此,大多数程序员会在 Connection 对象上显式调用 close()。

In your case, it should translate into something similar (and in this context, the finally block is guaranteed to run always)

在您的情况下,它应该转换为类似的东西(在这种情况下,finally 块保证始终运行)


try
{
 ThirdPartyInitialize();
 // use third party component in this try block
}
finally
{
 ThirdPartyTerminate();
}

This is similar to the how the Connection class is also used in most situations.

这类似于 Connection 类在大多数情况下的使用方式。

回答by Bill K

Your objects in Java really never need to be "Cleaned Up", GC Just works. Nearly every time I've seen someObject=null in code, it's been someone who didn't know what they were doing. There IS a theoretical case for this, but it's really an edge case and generally better handled in other ways like the recently added try with resource.

您在 Java 中的对象真的永远不需要“清理”,GC 就可以工作。几乎每次我在代码中看到 someObject=null 时,都是有人不知道他们在做什么。这有一个理论案例,但它实际上是一个边缘案例,通常可以通过其他方式更好地处理,例如最近添加的 try with resource。

If you have an external resource that needs to be cleaned up when an object is no longer used, that is another matter.

如果你有一个外部资源,当一个对象不再使用时需要清理,那是另一回事。

There are "Reference" classes that will hold a special type of Reference to your class--it will not stop garbage collection, but can notify you when the class is garbage collected (Through a callback if you like). Look up WeakReference, PhantomReference, etc.

有一些“引用”类将保存对您的类的特殊类型的引用——它不会停止垃圾收集,但可以在类被垃圾收集时通知您(如果您愿意,可以通过回调)。查找 WeakReference、PhantomReference 等。

These are reliable and work in a much more deterministic way than a actual "finalize" method would because the callback is outside your class, so you don't end up executing a method in some pre-deleted or half-deleted state and the problems that could cause.

这些是可靠的,并且以比实际的“finalize”方法更具确定性的方式工作,因为回调在您的类之外,因此您最终不会在某些预删除或半删除状态下执行方法以及问题这可能导致。

回答by Alexey

Two syntax sugar options:

两个语法糖选项:

1) There is a @Cleanupannotation in Lombok that mostly resembles C++ destructors (more):

1) Lombok 中有一个@Cleanup注释,它主要类似于 C++ 析构函数(更多):

@Cleanup
ResourceClass resource = new ResourceClass();

2) There is also try-with-resourcesstatement. For example:

2) 还有try-with-resources语句。例如:

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
  System.out.println(br.readLine());
}

回答by Glavo

You can use java.lang.ref.Cleanerin Java 9,

您可以在 Java 9 中使用java.lang.ref.Cleaner