Effective Java 2nd 中Item 7: Avoid finalizers關於Finalizer Guardian Idiom的論述:
If a subclass implementor overrides a superclass finalizer but forgets to invoke
it, the superclass finalizer will never be invoked. It is possible to defend against
such a careless or malicious subclass at the cost of creating an additional object
for every object to be finalized. Instead of putting the finalizer on the class
requiring finalization, put the finalizer on an anonymous class (Item 22) whose
sole purpose is to finalize its enclosing instance. A single instance of the
anonymous class, called a finalizer guardian, is created for each instance of the
enclosing class. The enclosing instance stores the sole reference to its finalizer
guardian in a private instance field so the finalizer guardian becomes eligible for
finalization at the same time as the enclosing instance. When the guardian is
finalized, it performs the finalization activity desired for the enclosing instance,
just as if its finalizer were a method on the enclosing class:
// Finalizer Guardian idiom public class Foo { // Sole purpose of this object is to finalize outer Foo object private final Object finalizerGuardian = new Object() { @Override protected void finalize() throws Throwable { ... // Finalize outer Foo object } }; ... // Remainder omitted }
Finalizer Guardian idiom是爲了防止該類被繼承且被覆蓋了finalize方法,並且沒有調用super.finalize()的情形(就是沒有使用所謂的finalizer chaining)。
因為在回收時去調Foo instance的finalize()會動態綁定到它子類的覆蓋方法上去,Foo的成員變量finalizerGuardian也會被回收,因此它的finalize()也會被調用,但是在這裡如果finalize了Foo的實例,finalizerGuardian自己怎麼辦?什麽都不寫,它會隱式回收自己嗎?我猜應該是會的,但不知道是怎麼實現的,因為覆蓋后相當於有關回收自己的代碼神馬都沒寫。
知道了,本身Object的finalize方法就是一個空方法,garbage collector無需任何多餘指示,只要一個空方法就可以進行回收了,被子類覆蓋后,新增的實現不影響原本對自己的回收。
2012.07.30 新增修改:
finalizerGuardian的回收機制如何被觸發?子類如果沒有finalizer chaining父类,那它只會finalize自己。
現在雖然沒有確鑿的資料證明,但這裡大膽結論:
當實例失去引用后即將被回收,它的成員變量也會先其而被回收,通過finalizerGuardian來finalize Foo對象,Foo對象只要被回收,它的成員自然而然就被強制回收。
// Manual finalizer chaining @Override protected void finalize() throws Throwable { try { ... // Finalize subclass state } finally { super.finalize(); } }
但這樣不禁又帶來一個疑問,父類對象被finalize之後,子類對象會不會被連帶finalize?
1. 父類對象被finalize之後,子類對象如果也會被finalize,這樣的話,finalizer chaining又有何意義呢?也就是說子類去覆蓋父類的finalize方法有何意義呢?
2. 如果父類對象被finalize之後,子類對象不會被finalize,那麼manual finalizer chaining就有意義了,它用finalize方法來finalize subclass state。
所以正確結論看來是2。
最終結論:
1. 當存在finalizer chaining時,父類對象失去引用需要被回收,garbage collector回收其成員,然後欲調用父類對象finalize方法,沒有,動態綁定去調用子類對象finalize方法,在try塊中finalize自身,在finally塊中連鎖調用super.finalize()方法,因此父類對象及其無被引用成員也被回收。
2. 當不存在finalizer chaining時,父類對象失去引用需要被回收,garbage collector欲調用父類對象finalize方法,沒有,動態綁定去調用子類對象finalize方法,在try塊中finalize自身,在 finally塊中沒有連鎖調用super.finalize()方法,但garbage collector會去回收父類成員(why?當父類對象不被引用時,其成員就有機會被GC,意思是成員也真正失去引用了),當涉及到finalizerGuardian時,調用其finalize方法,其中再調用了父類對象的finalize方法,因此父類對象被回收,失去引用的成員連帶也被回收。
此二結論還需要進一步被論證。