2011-08-12 62 views
5

我有一個帶有一個finalize()方法的伸縮構造函數的超類。爲了防止子類忘記調用super.finalize,我寫了一個終結者監護人(EJ Item 7)。Java終結者監護人似乎不工作?

public class Super { 

    public Super() {} 

    { 
     Object finalizerGuardian = new Object() { 
      @Override 
      protected void finalize() { 
       System.out.println("Finalizer guardian finalize"); 
       Super.this.finalize(); 
      } 
     }; 
    } 

    protected void finalize() { 
     System.out.println("Super finalize"); 
    } 

} 

下面是一個簡單的子類 -

public class Sub extends Super { 

    public Sub() {} 

    protected void finalize() { 
     System.out.println("Sub finalize"); 
    } 

    public static void main(String[] args) 
      throws InterruptedException { 
     if (1 == 1) { 
      Sub s1 = new Sub(); 
     } 
     Runtime.getRuntime().gc(); 
     Thread.sleep(10000); 
    } 
} 

當S1對象超出範圍,終結監護人的finalize()被調用,並且我從子類的finalize方法得到SYSO,但從來沒有從超級定稿中得到一個。

我很困惑。我是否從根本上誤解了某些東西?

免責聲明:我意識到終結者是危險的,而不是明智的,等等。仍試圖理解這裏的問題。

回答

8

有效的Java的終結監護人應當履行必要的終結邏輯本身(例如,調用Super執行實際敲定的一些方法),而不是調用finalize()方法,因爲在你的情況Super.this.finalize();實際上從子類調用覆蓋方法。

還要注意的是終結監護人應該是類的字段:

public class Super { 
    private final Object finalizerGuardian = new Object() { 
      @Override 
      protected void finalize() { 
       Super.this.doFinalize(); 
      } 
    }; 

    private void doFinalize() { 
     System.out.println("Super finalize"); 
    } 
} 
+0

在「它不工作」看到明顯的問題太趕上了。謝謝!! – Kal

2

你重載Super.finalize()方法Sub。這就是爲什麼它沒有被調用。

所以當你在「finalizerGuardian」呼叫Super.this.finalize();你實際上是呼叫Sub.finalize()

2

AS別人已經說過的動態調度是你的問題在這裏。但是,就我所見,代碼中還有一個主要的bug:你的finalizerGuardian只在初始化塊內部定義,這意味着一旦對象被初始化,對象就會超出範圍並且可以被GCed。

也就是說,即使您解決您的第一個問題(定義在類來處理定稿的東西最後的方法),你仍然需要保存finalizerGuardian的實例變量。

2

Super.finalize()是沒有得到調用,因爲子覆蓋它。嘗試添加Super._finalize()方法並從Super.finalize()和終結者監護人呼叫它。

另外,我覺得finalizerGuardian需要成爲Super領域。否則,即使Super對象仍然可以被強制訪問,它也可以收集垃圾。