私の経験では、 、オーバーライドする唯一の理由がありますObject.finalize()
が、それは非常に良い理由です。
finalize()
呼び出しを忘れた場合に通知するエラーログコードを配置しますclose()
。
静的分析は、些細な使用シナリオでのみ欠落を見つけることができ、別の回答で言及されているコンパイラーの警告は非常に単純な見方をしているので、些細なことをしないためには実際にそれらを無効にする必要があります。(私が知っているか聞いたことがある他のプログラマーよりもはるかに多くの警告が有効になっていますが、愚かな警告は有効になっていません。)
ファイナライズは、リソースが廃棄されないようにするための優れたメカニズムのように思えるかもしれませんが、ほとんどの人はそれを完全に間違った方法で見ます:彼らはそれを代替フォールバックメカニズム、自動的に保存する「セカンドチャンス」セーフガード忘れていた資源を処分することで これはまったく間違っています。所定の処理を行う方法は1つだけでなければなりません。常にすべてを閉じるか、ファイナライズが常にすべてを閉じるかのいずれかです。しかし、ファイナライズは信頼性が低いため、ファイナライズを行うことはできません。
ですから、私はMandatory Disposalと呼んでいるこのスキームがあり、プログラマーは、またはを実装するすべてを常に明示的に閉じる責任があると規定しています。(try-with-resourcesステートメントは依然として明示的な終了としてカウントされます。)もちろん、プログラマーは忘れることがあります。そのため、ファイナライズが必要になりますが、魔法の妖精としてではありません。それは呼び出されなかった、それはしませんCloseable
AutoCloseable
close()
を呼び出します。怠けすぎていたり、気が抜けすぎていたりする仕事をするためにそれに依存するプログラマー。したがって、必須の処分では、ファイナライズがそれを発見したときclose()
が呼び出されなかったことを検出すると、明るい赤色のエラーメッセージをログに記録し、プログラマーにすべての大文字を太字で伝えて、自分のものを修正します。
追加の利点として、うわさがそれを持っているので、必須処分にあなたがすることができ、「JVMは些細なファイナライズ()メソッド(Objectクラスで定義されたような何もせずにただ戻って、例えば、1つ)を無視する」というすべてのファイナライズを避けます次のfinalize()
ようにメソッドをコーディングすることにより、システム全体のオーバーヘッド(このオーバーヘッドがどれほどひどいかについては、alipの回答を参照)
@Override
protected void finalize() throws Throwable
{
if( Global.DEBUG && !closed )
{
Log.Error( "FORGOT TO CLOSE THIS!" );
}
//super.finalize(); see alip's comment on why this should not be invoked.
}
この背後にある考え方Global.DEBUG
は、static final
コンパイル時に値がわかっている変数であるためfalse
、コンパイラーはif
ステートメント全体に対してコードをまったく出力しないため、これは些細な(空の)ファイナライザーになります。クラスがファイナライザーを持たないかのように扱われることを意味します。(C#では、これは素晴らしい#if DEBUG
ブロックでが、何ができるのか、これはjavaです。ここでは、コードの見た目の単純さを頭に追加のオーバーヘッドを加えて支払います。)
強制廃棄についての詳細は、ドットネットでのリソースの廃棄についての追加の議論とともに、こちら:michael.gr:強制廃棄と「廃棄処分」の憎悪
finalize()
は少し台無しになっています。実装する場合は、同じオブジェクトの他のすべてのメソッドに対してスレッドセーフであることを確認してください。