终止一个对象与使它无效一样吗?
Is terminating an object is the same as nulling it?
所以我一直在经历"Effective Java 2nd Ed."
在第 7 项中,他谈到不使用终结器,因为它们会导致很多问题。
但是我们可以“提供一个明确的终止方法”而不是使用终结器,其中一个例子就是 close 语句。而且我不明白什么是“终止语句以及它们与终结器之间的区别是什么?
我得出的结论是,终止一个对象就像使它无效,从而释放资源。但我想我不太了解其中的区别。所以我感谢任何帮助。
谢谢!
But instead of using finalizers we can " provide an explicit
termination method" and an example of those is the close statement .
作者引用了 close()
方法,该方法提供了一种清理使用资源释放的对象的方法。
例如,当您创建和操作 InputStream
或 OutputStream
时,您不想依赖 Java 终结器(对于某些子classes 这些接口。例如,FileInputStream
class 定义了 finalize()
方法)释放与流关联的资源,但您想使用该方法由 API 提供:void close()
因为它作为终结器更可靠。
java.sql.Statement
的工作方式相同:它提供了一个 close()
方法来释放与语句实例关联的 JDBC 资源。
I came to the conclusion that terminating an object is like nulling it
thus the resourses is released .
将对象分配给 null
不需要释放所有应该释放的资源。此外,如果该对象或该对象的某个字段仍被另一个活着的对象引用,则该对象将不会被垃圾收集变得难以辨认
最后,垃圾回收可能也需要一些时间。
如果我们不需要使用该对象,为什么要等待?
显式终止方法与 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");
}
}
第一个覆盖继承自Object
的finalize()
方法。 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();
}
}
这个例子应该return:
termination example
Close Baz
Close Bar
Close Bar
Foo
的 finalize()
方法从未被调用,因为 Foo
未被垃圾回收。 JVM 有可用资源,因此为了性能优化,它不执行垃圾收集。此外 - 尽管完成了应用程序,但资源未被垃圾回收。即使是 Foo
的第二个创建实例也不是垃圾收集器,因为 JVM 有足够的资源可以茁壮成长。
第二个使用 ARM 的要好得多,因为它创建了两种资源(一个实现 java.io.Closeable
和一个实现 java.lang.AutoCloseable
,值得一提的是 Closeable
扩展了 AutoCloseable
,这就是它可用于 ARM 的原因)。 ARM 保证关闭这两种资源,在另一个抛出时关闭一个,等等。第二个展示了类似于 ARM 的东西,但是省去了很多不必要的样板代码。
让你成为更好的开发者的东西:
但它仍然不完美。程序员仍然需要记住关闭对象。 Java 中没有析构函数迫使开发人员要么记住关闭资源,要么记住使用 ARM,等等。有一个很好的设计模式(Venkat Subramaniam 很好地解释了)- Loan Pattern
。贷款模式的简单示例:
class Loan {
private Loan() {
}
public Loan doSomething(int m) {
System.out.println("Did something " + m);
if (new Random().nextBoolean()) {
throw new RuntimeException("Didn't see that commming");
}
return this;
}
public Loan doOtherThing(int n) {
System.out.println("Did other thing " + n);
return this;
}
private void close() {
System.out.println("Closed");
}
public static void loan(Consumer<Loan> toPerform) {
Loan loan = new Loan();
try {
toPerform.accept(loan);
} catch (Exception e) {
e.printStackTrace();
} finally {
loan.close();
}
}
}
你可以这样使用它:
class Main {
public static void main(String[] args) {
Loan.loan(loan -> loan.doOtherThing(2)
.doSomething(3)
.doOtherThing(3));
}
}
减轻了开发者关闭资源的负担,因为已经为他处理好了。如果其中一个方法抛出异常,那么它就会被处理,开发人员就不必费心了。 close 方法和构造函数是私有的,不会诱使开发人员使用它们。
所以我一直在经历"Effective Java 2nd Ed."
在第 7 项中,他谈到不使用终结器,因为它们会导致很多问题。
但是我们可以“提供一个明确的终止方法”而不是使用终结器,其中一个例子就是 close 语句。而且我不明白什么是“终止语句以及它们与终结器之间的区别是什么?
我得出的结论是,终止一个对象就像使它无效,从而释放资源。但我想我不太了解其中的区别。所以我感谢任何帮助。
谢谢!
But instead of using finalizers we can " provide an explicit termination method" and an example of those is the close statement .
作者引用了 close()
方法,该方法提供了一种清理使用资源释放的对象的方法。
例如,当您创建和操作 InputStream
或 OutputStream
时,您不想依赖 Java 终结器(对于某些子classes 这些接口。例如,FileInputStream
class 定义了 finalize()
方法)释放与流关联的资源,但您想使用该方法由 API 提供:void close()
因为它作为终结器更可靠。
java.sql.Statement
的工作方式相同:它提供了一个 close()
方法来释放与语句实例关联的 JDBC 资源。
I came to the conclusion that terminating an object is like nulling it thus the resourses is released .
将对象分配给 null
不需要释放所有应该释放的资源。此外,如果该对象或该对象的某个字段仍被另一个活着的对象引用,则该对象将不会被垃圾收集变得难以辨认
最后,垃圾回收可能也需要一些时间。
如果我们不需要使用该对象,为什么要等待?
显式终止方法与 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");
}
}
第一个覆盖继承自Object
的finalize()
方法。 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();
}
}
这个例子应该return:
termination example
Close Baz
Close Bar
Close Bar
Foo
的 finalize()
方法从未被调用,因为 Foo
未被垃圾回收。 JVM 有可用资源,因此为了性能优化,它不执行垃圾收集。此外 - 尽管完成了应用程序,但资源未被垃圾回收。即使是 Foo
的第二个创建实例也不是垃圾收集器,因为 JVM 有足够的资源可以茁壮成长。
第二个使用 ARM 的要好得多,因为它创建了两种资源(一个实现 java.io.Closeable
和一个实现 java.lang.AutoCloseable
,值得一提的是 Closeable
扩展了 AutoCloseable
,这就是它可用于 ARM 的原因)。 ARM 保证关闭这两种资源,在另一个抛出时关闭一个,等等。第二个展示了类似于 ARM 的东西,但是省去了很多不必要的样板代码。
让你成为更好的开发者的东西:
但它仍然不完美。程序员仍然需要记住关闭对象。 Java 中没有析构函数迫使开发人员要么记住关闭资源,要么记住使用 ARM,等等。有一个很好的设计模式(Venkat Subramaniam 很好地解释了)- Loan Pattern
。贷款模式的简单示例:
class Loan {
private Loan() {
}
public Loan doSomething(int m) {
System.out.println("Did something " + m);
if (new Random().nextBoolean()) {
throw new RuntimeException("Didn't see that commming");
}
return this;
}
public Loan doOtherThing(int n) {
System.out.println("Did other thing " + n);
return this;
}
private void close() {
System.out.println("Closed");
}
public static void loan(Consumer<Loan> toPerform) {
Loan loan = new Loan();
try {
toPerform.accept(loan);
} catch (Exception e) {
e.printStackTrace();
} finally {
loan.close();
}
}
}
你可以这样使用它:
class Main {
public static void main(String[] args) {
Loan.loan(loan -> loan.doOtherThing(2)
.doSomething(3)
.doOtherThing(3));
}
}
减轻了开发者关闭资源的负担,因为已经为他处理好了。如果其中一个方法抛出异常,那么它就会被处理,开发人员就不必费心了。 close 方法和构造函数是私有的,不会诱使开发人员使用它们。