通過“合成”方法創建新類時,永遠不必擔心對那個類的成員對象的收尾工作。每個成員都是一個獨立的對象,所以會得到正常的垃圾收集以及收尾處理——無論它是不是不自己某個類一個成員。但在進行初始化的時候,必須覆蓋衍生類中的finalize()方法——如果已經設計了某個特殊的清除進程,要求它必須作為垃圾收集的一部分進行。覆蓋衍生類的finalize()時,務必記住調用finalize()的基礎類版本。否則,基礎類的初始化根本不會發生。下面這個例子便是明證:
//: Frog.java // Testing finalize with inheritance class DoBaseFinalization { public static boolean flag = false; } class Characteristic { String s; Characteristic(String c) { s = c; System.out.println( "Creating Characteristic " + s); } protected void finalize() { System.out.println( "finalizing Characteristic " + s); } } class LivingCreature { Characteristic p = new Characteristic("is alive"); LivingCreature() { System.out.println("LivingCreature()"); } protected void finalize() { System.out.println( "LivingCreature finalize"); // Call base-class version LAST! if(DoBaseFinalization.flag) try { super.finalize(); } catch(Throwable t) {} } } class Animal extends LivingCreature { Characteristic p = new Characteristic("has heart"); Animal() { System.out.println("Animal()"); } protected void finalize() { System.out.println("Animal finalize"); if(DoBaseFinalization.flag) try { super.finalize(); } catch(Throwable t) {} } } class Amphibian extends Animal { Characteristic p = new Characteristic("can live in water"); Amphibian() { System.out.println("Amphibian()"); } protected void finalize() { System.out.println("Amphibian finalize"); if(DoBaseFinalization.flag) try { super.finalize(); } catch(Throwable t) {} } } public class Frog extends Amphibian { Frog() { System.out.println("Frog()"); } protected void finalize() { System.out.println("Frog finalize"); if(DoBaseFinalization.flag) try { super.finalize(); } catch(Throwable t) {} } public static void main(String[] args) { if(args.length != 0 && args[0].equals("finalize")) DoBaseFinalization.flag = true; else System.out.println("not finalizing bases"); new Frog(); // Instantly becomes garbage System.out.println("bye!"); // Must do this to guarantee that all // finalizers will be called: System.runFinalizersOnExit(true); } } ///:~
DoBasefinalization類只是簡單地容納了一個標志,向分級結構中的每個類指出是否應調用super.finalize()。這個標志的設置建立在命令行參數的基礎上,所以能夠在進行和不進行基礎類收尾工作的前提下查看行為。
分級結構中的每個類也包含了Characteristic類的一個成員對象。大家可以看到,無論是否調用了基礎類收尾模塊,Characteristic成員對象都肯定會得到收尾(清除)處理。
每個被覆蓋的finalize()至少要擁有對protected成員的訪問權力,因為Object類中的finalize()方法具有protected屬性,而編譯器不允許我們在繼承過程中消除訪問權限(“友好的”比“受到保護的”具有更小的訪問權限)。
在Frog.main()中,DoBaseFinalization標志會得到配置,而且會創建單獨一個Frog對象。請記住垃圾收集(特別是收尾工作)可能不會針對任何特定的對象發生,所以為了強制采取這一行動,System.runFinalizersOnExit(true)添加了額外的開銷,以保證收尾工作的正常進行。若沒有基礎類初始化,則輸出結果是:
not finalizing bases Creating Characteristic is alive LivingCreature() Creating Characteristic has heart Animal() Creating Characteristic can live in water Amphibian() Frog() bye! Frog finalize finalizing Characteristic is alive finalizing Characteristic has heart finalizing Characteristic can live in water
從中可以看出確實沒有為基礎類Frog調用收尾模塊。但假如在命令行加入“finalize”自變量,則會獲得下述結果:
Creating Characteristic is alive LivingCreature() Creating Characteristic has heart Animal() Creating Characteristic can live in water Amphibian() Frog() bye! Frog finalize Amphibian finalize Animal finalize LivingCreature finalize finalizing Characteristic is alive finalizing Characteristic has heart finalizing Characteristic can live in water
盡管成員對象按照與它們創建時相同的順序進行收尾,但從技術角度說,並沒有指定對象收尾的順序。但對於基礎類,我們可對收尾的順序進行控制。采用的最佳順序正是在這裡采用的順序,它與初始化順序正好相反。按照與C++中用於“破壞器”相同的形式,我們應該首先執行衍生類的收尾,再是基礎類的收尾。這是由於衍生類的收尾可能調用基礎類中相同的方法,要求基礎類組件仍然處於活動狀態。因此,必須提前將它們清除(破壞)。