5

finalize() メソッドを持つテレスコープ コンストラクターを持つスーパー クラスがあります。サブクラスが super.finalize の呼び出しを忘れるのを防ぐために、ファイナライザー ガーディアン (EJ Item 7 ) をそのように記述しました。

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 を取得しますが、スーパーの finalize から SYSO を取得することはありません。

よくわかりません。私は何か根本的に誤解していますか?

免責事項:ファイナライザーは危険であり、お勧めできないことなどを認識しています。ここで問題を理解しようとしています。

4

4 に答える 4

8

Super効果的なJavaのファイナライザーガーディアンは、メソッドを呼び出すのではなく、必要なファイナライズロジック自体を実行する必要があります(たとえば、実際のファイナライズを実行するメソッドを呼び出す)。これは、実際にはサブクラスからオーバーライドされたメソッドを呼び出す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");
    }
}
于 2011-08-12T14:35:23.833 に答える
2

他の人がすでに言っているように、ここでは動的ディスパッチが問題です。しかし、私が見る限り、あなたのコードにはもう 1 つの大きなバグがあります。あなたの finalizerGuardian は初期化ブロック内でのみ定義されています。これは、オブジェクトが初期化されるとすぐに、オブジェクトがスコープから外れて GC される可能性があることを意味します。

つまり、最初の問題を (ファイナライズ処理を処理するクラスで final メソッドを定義することによって) 修正したとしても、 finalizerGuardian をインスタンス変数に保存する必要があります。

于 2011-08-12T14:39:12.787 に答える
2

Super.finalize()Sub がそれをオーバーライドするため、呼び出されません。メソッドを追加して、ファイナライザー ガーディアンSuper._finalize()から呼び出してみてください。Super.finalize()

finalizerGuardianまた、のフィールドである必要があると思いますSuper。そうしないと、スーパー オブジェクトがまだ強力に到達可能であっても、ガベージ コレクションが実行される可能性があります。

于 2011-08-12T14:39:49.133 に答える
2

Super.finalize()のメソッドをオーバーロードしていSubます。呼ばれないのはそのためです。

したがって、あなたが " finalizerGuardian" 呼び出しSuper.this.finalize();ているときは、実際に呼び出していることになりますSub.finalize()

于 2011-08-12T14:36:22.850 に答える