1 重点关注
1.1 终止方法的写法
try finally 见3.1
1.2 终结方法的写法
finalize()见3.2
1.3 使用终结方法的场景
a 当对象的所有者忘记调用1.2显式终止方法时,终结方法可以充当安全网。(FileInputStream,FileOutputStream,Timer,Connection 的 终结方法finalize)
b 本地对等体不拥有关键资源的前提下,可以使用
1.4 什么是本地对等体
本地对等体(是一个本地对象,普通对象通过本地方法委托给一个本地对象。)不是一个普通对象,垃圾回收器不会回收它。一般情况下,终结方法需要能够完成所有必要的工作释放资源,如果需要即时释放资源,那么就需要给本地对等体指定一个显式的终止方法。 参见3.3案例(疑问)
我理解比如像windows系统的生成的中间文件等可以使用本地对等体
1.5 终结方法链继承后,子类必须在finally执行超类终结方法
终结方法链不会自动执行,如果类有终结方法,并且子类覆盖了终结方法,则子类的终结方法必须手工调用超类的终结方法。你应该在try块中终结子类,并在相应的finally块中调用超类的终结方法。参见3.4
1.6 终结方法守卫者使用场景
如果需要把终结方法与共有的final类关联起来,请考虑使用终结方法守卫者,以确保及时子类的终结方法未能调用super.finalize,该终结方法也会被执行(见3.5)
通俗的说,就是父类的匿名内部类添加终结方法,所以子类即使覆盖父类终结方法并且没有调用父类的终结方法也无所谓,因为父类的匿名内部类会调用终结方法
2 课程内容
2.1 参考重点关注
2.2 为什么其他场景禁止使用终结方法
a 终结方法(finalizer)通常是不可预测的,也是很危险的,一般情况下是不必要的。使用终结方法会导致行为不稳定,降低性能,以及可移植性问题。
b 终结方法并不一定会被及时的执行,从一个对象变得不可到达开始,,到它的终结方法被执行,,所花费的时间是任意长的。JVM会延迟执行终结方法。
c Java语言规范不能保证终结方法会被执行,不应该依赖终结方法来更新重要的持久状态。
d System.gc()
和System.runFinalization()
方法增加了终结方法被执行的机会,但是它们并不保证终结方法一定会被执行。 参考3.2
e 使用终结方法或者清洁器会导致要种的性能损失
3 代码演练
3.1 显式使用终止方法
Foo
package com.ddwei.test.core.chapter7.demo1; import lombok.Getter; @Getter public class Foo { private String status; public Foo(){ this.status = "1"; } public void doSomthing(){ if("0".equals(status)){ throw new IllegalArgumentException(); } //do something } public void terminate(){ status = "0"; } }
Test
package com.ddwei.test.core.chapter7.demo1; public class FooTest { public static void main(String[] args) { Foo foo = new Foo(); try { foo.doSomthing(); } finally { foo.terminate(); } } }
3.2 终结方法
demo
package com.ddwei.test.core.chapter7.demo2; import java.io.FileInputStream; import java.io.FileNotFoundException; public class Test { FileInputStream fileInputStream = new FileInputStream(""); public Test() throws Throwable { //终结方法 finalize(); //这两个终结方法并不保证一定会执行 System.gc(); System.runFinalization(); //这两个方法声称保证终结方法一定会执行,但是已经被废弃 System.runFinalizersOnExit(true); Runtime.runFinalizersOnExit(true); } }
3.3 本地对等体(Native Peer)
demo
package com.ddwei.test.core.chapter7.demo3; import gnu.java.util.prefs.gconf.GConfNativePeer; //导入依赖的package包/类 public class AAA { /** * Builds a GConf key string suitable for operations on the backend. * * @param key The key to convert into a valid GConf key. * @return A valid Gconf key. */ private String getGConfKey(String key) { String nodeName = ""; // strip key // please, note that all names are unescaped into the native peer key = GConfNativePeer.escapeString(key); if (this.node.endsWith("/")) { nodeName = this.node + key; } else { nodeName = this.node + "/" + key; } return nodeName; } }
3.4 子类覆盖终结方法,必须在finally块调用超类的终结方法
try { // Do whatever the finalization is } finally { super.finalize(); }
3.5 终结方法守卫者
public class FinalizerGuardian { //匿名内部类--终结方法守卫者 private final Object ft = new Object() { @Override protected void finalize() throws Throwable { System.out.println("匿名内部类的终结方法执行了"); } }; //由于终结方法被子类覆盖,并且子类没有调用超类终结方法,所以不会被执行。 @Override protected void finalize() throws Throwable { System.out.println("超类的终结方法执行了"); } public static void main(String[] args) { FinalizerGuardianSon fgs=new FinalizerGuardianSon(); fgs=null; System.gc(); } } class FinalizerGuardianSon extends FinalizerGuardian { @Override protected void finalize() throws Throwable { System.out.println("子类的终结方法执行了"); } }
参考:https://blog.csdn.net/zh123456_789/article/details/111874429