1

ジャワ

Java には、「 Finalizer Guardian 」と呼ばれるイディオムがあり、サブクラスがスーパークラスのファイナライザーをオーバーライドするのを防ぎますが、それを呼び出すのを忘れます。以下は、Effective Java Item7の例です。

// 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
}

この手法を使用すると、ファイナライザーを持つサブクラスがスーパークラスのファイナライザーを呼び出さなくても、プライベート オブジェクトはスーパークラスのファイナライズ コードを実行します。


C#

ただし、C# in a Nutshellのセクション「Calling Dispose from a Finalizer」には、次のような例があります。

class Test : IDisposable {
  public void Dispose() // NOT virtual {
    Dispose (true);
    GC.SuppressFinalize (this); // Prevent finalizer from running.
  }

  protected virtual void Dispose (bool disposing) {
    if (disposing) {
      // Call Dispose() on other objects owned by this instance.
      // You can reference other finalizable objects here.
      // ...
    }
    // Release unmanaged resources owned by (just) this object.
    // ...
  }

  ˜Test() {
    Dispose (false);
  }
} 

また、著者は次のようにも述べています。

このフラグは 、ファイナライザーからの「最終手段モード」ではなくdisposing、メソッドから「適切に」呼び出されていることを意味します。set toでDispose呼び出された場合、このメソッドは通常、ファイナライザーを使用して他のオブジェクトを参照しないでください (そのようなオブジェクト自体がファイナライズされ、予測できない状態になる可能性があるため)。disposingfalse


質問

しかし、Java のファイナライザー ガーディアンのイディオムを確認すると、内側のプライベート ガーディアン オブジェクトは、ファイナライザー自体を持つことができる外側のオブジェクトを実際に参照/ファイナライズします。これは、 C# の作成者が一言で言えば述べたことに違反しています。

「ファイナライザーで他のファイナライズ可能なオブジェクトを参照する」ことがJavaでは可能であるのにC#では不可能な理由に興味があります。回答ありがとうございます。

4

3 に答える 3

1

それほど単純ではないと思います。.net と Java の他のオブジェクトを同様に参照できると思いますが、他のオブジェクトが予測できない状態にあるという同じ問題が存在します。それらを完全に理解するには、両方の内部の仕組みを研究する必要がありますが、私は Java をそれほど深く知りません。それらは非常に似ていると思います。ところで、このファイナライザー ガーディアンは怪しく見えます。

于 2014-02-14T06:13:16.537 に答える
1

ファイナライザー ガーディアンのコードは示していませんが、ファイナライズ可能なオブジェクトが元のオブジェクトへの参照を保持しないようにすることをお勧めします。代わりに、クリーンアップが必要なオリジナルの側面は、ファイナライズ可能なオブジェクト内にカプセル化する必要があります (おそらくAtomicReferenceまたはを使用AtomicInteger)。たとえば、OS ファイル ハンドルをカプセル化するオブジェクトは、AtomicInteger. 外側のオブジェクトが放棄された場合、外側のオブジェクトにアクセスすることなく、ハンドルをクリーンアップできます。外側のオブジェクトがファイルを閉じるように求められた場合、その要求を内側のオブジェクトに中継できます。AtomicIntegerハンドルが格納される場所 (これにより、ファイルを 1 回だけ閉じることができます)。

于 2014-03-07T20:31:10.927 に答える