所以我一直在经历" Effective Java 2nd Ed。"
在第7项中,他谈到不使用终结器,因为它们可能会导致很多问题。
但我们可以"而不是使用终结器。提供明确的终止方法"其中一个例子就是密切的陈述。我不明白什么是"终止语句和它们与终结者之间的区别是什么?
我得出结论,终止一个对象就像归零一样,因此资源被释放。但我想我不太了解它的区别。所以我感谢任何帮助。
谢谢!
答案 0 :(得分:8)
但我们可以“提供一个明确的,而不是使用终结器 终止方法“和那些例子是密切的陈述。
作者提到了一种close()
方法,该方法提供了一种清理使用资源释放的对象的方法。
例如,当您创建和操作InputStream
或OutputStream
时,您不希望依赖Java终结器(可能存在这些接口的某些子类。例如,它是定义FileInputStream
方法的finalize()
类的情况,以释放与流关联的资源,但您希望使用API提供的方法来执行此操作:void close()
因为它是终结者更可靠。
java.sql.Statement
以相同的方式工作:它提供close()
方法来释放与语句实例关联的JDBC资源。
我得出结论,终止一个对象就像归零一样 因此资源被释放。
将对象分配给null
将不必释放应该释放的所有资源。此外,如果对象或对象的一个字段仍被另一个生物对象引用,则该对象将难以被垃圾收集。
最后,收集垃圾可能还需要一段时间 如果我们不需要使用该对象,为什么还要等待?
答案 1 :(得分:1)
显式终止方法和finalize()
之间的主要区别在于第二个不能保证被调用。它最终在垃圾收集期间被调用,这可能是诚实的,从未发生过。让我们考虑以下三个类。
class Foo {
@Override
public void finalize() {
System.out.println("Finalize Foo");
}
}
class Bar implements Closeable {
@Override
public void close() {
System.out.println("Close Bar");
}
}
class Baz implements AutoCloseable {
@Override
public void close() {
System.out.println("Close Baz");
}
}
第一个覆盖从finalize()
继承的Object
方法。 Foo
和Bar
实现由ARM(自动资源管理)处理的两个接口。
Foo foo = new Foo();
new Foo();
try (Bar bar = new Bar(); Baz baz = new Baz()) { // this is ARM
System.out.println("termination example");
}
Bar bar = null;
try {
bar = new Bar();
// ...
} finally {
if (bar != null) {
bar.close();
}
}
此示例应返回:
termination example
Close Baz
Close Bar
Close Bar
finalize()
的{{1}}方法永远不会被调用,因为Foo
不是垃圾回收。 JVM具有可用资源,因此对于性能优化,它不执行垃圾收集。此外 - 如果资源不是垃圾收集,尽管完成应用程序的事实。即使是第二个创建的Foo
实例也不是Garbage Collected,因为有足够的资源让JVM蓬勃发展。
第二个使用ARM的方法要好得多,因为它创建了两个资源(一个实现Foo
,一个实现java.io.Closeable
,值得一提的是java.lang.AutoCloseable
扩展{{1} },这就是为什么它可用于ARM)。 ARM保证这两种资源都要关闭,当另一种抛出时关闭一个等等。第二个类似于ARM,但节省了大量不必要的样板代码。
让您成为更好的开发者的东西:
但它仍然不完美。程序员仍然有责任记住关闭对象。 Java中没有析构函数会迫使开发人员记住关闭资源,记得使用ARM等等。有一个很好的设计模式(很好地解释了Venkat Subramaniam) - Closeable
。贷款模式的一个简单例子:
AutoCloseable
你可以这样使用它:
Loan Pattern
它减轻了开发人员关闭资源的负担,因为它已经为他处理了。如果这些方法中的一个抛出,则处理它并且开发人员不必费心。 close方法和构造函数是私有的,不会诱使开发人员使用它们。