【概要】
サブクラスの実装で finalize() メソッドがオーバーライドされており、その実装が誤ってスーパークラスの finalize() メソッドを呼び出し忘れてしまっても安全にスーパークラスのファイナライズ処理が行えるようにしたい。

【キーワード】
ファイナライザ・ガーディアン、Finalizer Guardian、Finalize

【参考】
Effective Java プログラミング言語ガイド

【詳細】
ファイナライザ・ガーディアンとは、継承される可能性のあるクラスを定義する際に、サブクラスの実装によって finalize() メソッドが呼び出されなくなってしまう危険性を回避するためのものである。

例えば次のような Connection クラスがあるとする。

public class Connection {
 ...
 protected void finalize() throws Throwable {
  if (isConnected()) {
   disconnect();
  }
 }
 ...
}
Connection クラスの finalize メソッド内では、 disconnect() が呼び出されなかった場合にも、インスタンスが GC される際に isConnected() が true であれば disconnect() が呼び出されるよう安全策がとられている。

このクラスを利用するサブクラスを実装する際、次の BadSubConnection クラスのように、Connection クラスで提供されている安全策を無効化してしまう危険性のある実装を行うことができてしまう。

releaseRelatedResources() メソッドの処理中に例外が発生した場合、 super.finalize() が呼び出されずに finalize() メソッドが終了してしまうため、Connection クラスで提供されている機構が機能しない。

public class BadSubConnection extends Connection {
 ...
 protected void finalize() throws Throwable {
  releaseRelatedResources();
  super.finalize();
 }
 ...
}
もちろん、サブクラスの実装が次の GoodSubConnection のようにきちんと実装されていれば何の問題もない。

しかし、どのように利用されようとも安定性を崩さないように実装するべきである。

public class GoodSubConnection extends Connection {
 ...
 protected void finalize() throws Throwable {
  try {
   releaseRelatedResources();
  } finally {
   super.finalize();
  }
 }
 ...
}
ファイナライザ・ガーディアンを利用した Connection クラスの実装は次のようになる。

Connection の finalize() メソッドを直接オーバーライドするのではなく、フィールド finalizerGuardian の finalize() メソッドをオーバーライドする。

public class Connection {
 private final Object finalizerGuardian = new Object() {
  protected void finalize() throws Throwable {
   if (isConnected()) {
    disconnect();
   }
  }
 }
 ...
}
このように実装しておくと、GoodSubConnection はもちろんのこと、 サブクラスの実装が仮に BadSubConnection のようになっていても finalizerGuardian の finalize() が必ず呼び出されるため、 変更前の Connection よりも安全に利用できるようになる。