finalizeメソッドの意味を理解しようとした方法

最近、私はある会社にJavaプログラマーとしての面接に招待されました。 インタビューでは、finalizeメソッドの動作について話しました。 私はこの方法の仕事について表面的な考えしか持たず、面接官にそれについての説明をすることができませんでした。 したがって、インタビューの後、私は間違いに取り組み、それを解明しなければなりませんでした。



私の知識は、ガベージコレクターがオブジェクトの破棄を開始するときにfinalizeメソッドが呼び出されるという事実に限られていました。 そして、私は彼が何のために役立っているのかよくわかりませんでした。 私はそれがデストラクタのようなものだと思いました。それは、特定のリソースが不要になった後、他のオブジェクトに保存されているリソースでさえも解放できるということです。



だから、最初に理解することは目的でした。



このメソッドは、このメソッドが呼び出されるオブジェクトが占有しているシステムリソースを自動的に解放することを目的としています。 たとえば、あるリソースへの接続が不要になったときに閉じなければならないことを常に覚えておくのは便利なようです。



データをクリーンアップするためにファイナライズに依存しないでください。 まず、呼び出されるという保証はありません。 オブジェクトへのリンクがある可能性があります。 第二に、メソッドがいつ呼び出されるかという保証はありません。 これは、オブジェクトがアセンブリ可能になり、finalizeメソッドがその中でオーバーライドされた場合、すぐに呼び出されるのではなく、このために特別に作成されたスレッドによって処理されるキューに配置されるという事実によるものです。 finalizeメソッドがオーバーライドされるオブジェクトのみがファイナライズキューに入ることに注意してください。



このメソッドはまったく呼び出されない可能性があります。 これは、オブジェクトがガベージコレクターに既にアクセス可能であり、プログラムが終了したときに発生する可能性があります。



このメソッドの興味深い機能は、これを何らかの変数に割り当てることで、オブジェクトに再びアクセスできるようになることです。ただし、これはお勧めできません。 オブジェクトを復元するとき、ファイナライズは再び呼び出されません



別のまれなことが起こるかもしれません。 finalizeメソッドが実装されているクラスAがあります。 クラスBを作成し、Aを拡張します。ファイナライズについては忘れます。 クラスBオブジェクトには多くのデータが含まれています。 クラスBのオブジェクトが不要になると、それらはファイナライズキューに入り、このキューを渡してすぐに破棄するのではなく、しばらくの間メモリを占有します。



別の欠点は、スーパークラスを再定義する場合、スーパークラスのfinalizeメソッドを呼び出すことを覚えておく必要があることです。 開発者は電話しません-誰も電話しません。



finalizeメソッドでスローされた例外は、ファイナライザースレッドによって処理されません。 ほとんどの場合、このトラックレースは追跡できません。



アセンブリ可能なオブジェクトに対してfinalizeメソッドが実行されたことを確認する方法が1つあります: System.runFinalization()またはRuntime.getRuntime()を呼び出します。RunFinalization()。 メソッドの終了は、ファイナライズに使用できるオブジェクトのすべてのメソッドが完了した場合にのみ実行されます



私自身、特別な必要なしにこの方法を使用することは価値がないと結論し、2年半の練習でこの特別な必要のあるケースにまだ遭遇していません。



ファイナライズする代わりに、java.ioでcloseメソッドを記述し、finallyブロックで呼び出すことをお勧めします。 欠点は、使用後にリソースを閉じる必要があることを開発者が覚えておく必要があることです。 Java SE 7は、そのtry-with-resourcesで救助に来ました



しかし、この方法には何らかの理由があります。 どこでどのように使用できますか? 使用例はありますか?



ファイナライズは、リソースを閉じる最後の機会として使用できますが、最初または唯一の試行として使用することはできません。 つまり クライアントが、たとえば、リソースを表すオブジェクトのcloseメソッドを呼び出すことができるという事実に加えて。 またはそれを忘れるかもしれません。 その後、彼を助けようとすることができます。 これは、たとえばFileInputStream.javaクラスで行われます。



protected void finalize() throws IOException { if ((fd != null) && (fd != FileDescriptor.in)) { /* * Finalize should not release the FileDescriptor if another * stream is still using it. If the user directly invokes * close() then the FileDescriptor is also released. */ runningFinalize.set(Boolean.TRUE); try { close(); } finally { runningFinalize.set(Boolean.FALSE); } } }
      
      







このアプローチは、Javaライブラリでよく使用されます。



PS。 純粋な真実として書かれているものを受け取らないようお願いします。 読んだ資料の理解方法だけを書きました。 追加、批判、訂正を喜んで受け入れます。



使用された文献のリスト:

Java Finalizationのメモリ保持の問題を処理する方法

Java Finalizeメソッド呼び出し

java.lang。 クラスオブジェクト

Javaのfinalizeメソッドに関する10ポイント-チュートリアルの例

ハブラハブ。 ファイナライズとファイナライザー



All Articles