web-dev-qa-db-ja.com

Java.lang.Objectのfinalize()メソッドが「保護されている」のはなぜですか?

好奇心から、

finalize()メソッドのアクセス修飾子がprotectedとして作成されるのはなぜですか。なぜpublicできないのですか?誰かが私にこれの背後にある特定の理由を説明できますか?

また、finalize()メソッドは一度しか呼び出されないことを知りました。私のプログラムで内部的にそれを2回呼び出した場合、何が起こっていますか?ガベージコレクターは再びこれを呼び出しますか?

private void dummyCall() {
    try {
        finalize();
        finalize();
    } catch (Throwable e) {
        e.printStackTrace();//NOT REACHES EXCEPTION
    }
}
35
bragboy

私は別の質問であなたの質問に答えます:

finalizeメソッドを保護すべきではないのはなぜですか?

一般に、物事はできるだけプライベートに保つようにしてください。それがカプセル化のすべてです。それ以外の場合は、すべてpublicを作成できます。 finalizeprivateにすることはできません(派生クラスがそれにアクセスしてオーバーライドできるようにする必要があるため)少なくともprotectedにする必要がありますが、それが望ましくないときにより多くのアクセス?


あなたのコメントをもっと注意深く読んだ後、私は今あなたの要点を理解していると思います。すべてがJava.lang.Objectから派生し、その結果protectedメンバーにアクセスするため、それ(またはJava.lang.Objectのメソッド)には何の違いもないため、 publicではなくprotectedになります。個人的には、これをJavaの設計上の欠陥として数えます。これは確かにC#で修正されています。問題は、finalizeが保護されている理由ではありません。それで大丈夫です。実際の問題は、基本クラス型のオブジェクト参照を介して基本クラスの保護されたメソッドを呼び出せないようにする必要があることです。 Eric Lippertが ブログエントリ 保護されたメンバーにそのような種類のアクセスを許可することが悪い考えである理由について議論しています この質問でスタックオーバーフローについてさらに詳しく説明します

24
Mehrdad Afshari

Finalize()メソッドのアクセス修飾子が保護されているのはなぜですか。なぜ公開できないのですか?

これは、JVM以外から呼び出されるべきではないため、パブリックではありません。ただし、その動作を定義する必要があるサブクラスによってオーバーライドできるように、保護する必要があります。

私のプログラムでそれを2回呼び出した場合、内部的に何が起こっていますか?

あなたはそれをあなたが望むすべてのものと呼ぶことができ、結局のところそれは単なるメソッドです。ただし、public static void main(String [] args)と同様に、JVMにとって特別な意味があります。

ガベージコレクターは再びこれを呼び出しますか?

はい

23
Kevin
  • finalizeはGCのみが呼び出すことを意味しますなので、パブリックアクセスは必要ありません
  • finalizeは、一度だけ呼び出されることが保証されていますgcによって、それを自分で呼び出すと、gcがそれを知らないため、この保証は破られます。
  • オーバーライドしているクラスはfinalizeを公開できますが、これは上記の理由から悪いと思います
  • finalizeがスローした例外がGCのファイナライザスレッドを強制終了する可能性があるため、finalizeには多くのコードを含めないでください。

Finalize()に反対する

  • ネイティブリソースまたはdispose()またはclose()の呼び出しを必要とするリソースを管理すると、jvmがメモリ不足になったときにのみ解放されるため、バグを見つけにくくなる可能性があります。手動でリソースを解放する必要があります。 Finalizeは、リソースリークのデバッグ、またはリソースを手動で管理するのが面倒な場合にのみ使用してください。
  • finalizeはgcの追加スレッドで呼び出され、リソースのロックなどの問題を引き起こす可能性があります。
  • weakReferenceやReferenceQueueなどの参照クラスは、クリーンアップを処理するための(かなり複雑な)代替手段であり、ネイティブリソースのfinalize()と同じ問題が発生する可能性があります。

上記のステートメントのエラーに注意してください、私は少し疲れています:-)

12
josefx

それを議論する このリンク をチェックしてください。

基本的には、JVM(ガベージコレクター)によってのみ呼び出されるため、privateであることが最も理にかなっています。しかし、サブクラスがfinalize()の一部として親finalize()メソッドを呼び出すことができるようにするには、protectedである必要があります。

Edit-そして一般的な注意-finalize()メソッドの使用は、呼び出されることを保証する方法がないため、通常はお勧めしません。それはあなたがそれを使う機会がないことを意味するわけではありませんが、それはまれです。)

3
froadie

finalize()が1回だけ呼び出される部分は、GCからの呼び出しにのみ適用されます。オブジェクトに非表示のフラグ「finalize()がGCによって呼び出されました」があり、GCがそのフラグをチェックしてオブジェクトの処理方法を知っていると想像できます。フラグは、finalize()への独自の手作りの呼び出しによる影響を受けません。

ファイナライズについては、ハンスベーム(ガベージコレクションに関する彼の研究で有名)の この記事 をお読みください。これはファイナライズに関する目を見張るものです。特に、Boehmは、ファイナライズが必然的に非同期である理由を説明しています。当然ですが、ファイナライズは強力なツールですが、特定の仕事に適したツールとなることはほとんどありません。

3
Thomas Pornin

これはpublic(またはデフォルトのアクセス)ではありません。オブジェクトがガベージコレクションされたときに内部的にJVMによって呼び出されることを意図しているためですnotは他のものによって呼び出されることを意味します。そして、それはprivateではありません。これは、オーバーライドされることを意図しており、プライベートメソッドをオーバーライドできないためです。

私のプログラムでそれを2回呼び出した場合、内部的に何が起こっていますか?ガベージコレクターはこれを再度呼び出しますか?

おそらくそうですが、これが何らかの意味をなすシナリオを想像するのは困難です。finalize()のポイントは、オブジェクトがガベージコレクションされたときにクリーンアップを行うことです。そして、それでもうまくいかないので、実際に実験するのではなく、完全に回避する必要があります。

2

finalize()は、オブジェクトが収集されたときにリソースをクリーンアップするためにJVMによってのみ使用されます。クラスがコレクションに対して実行する必要があるアクションを定義することは合理的であり、そのためにsuper.finalize()にアクセスする必要があります。外部プロセスがオブジェクトを収集するタイミングを制御できないため、外部プロセスがfinalize()を呼び出すことは実際には意味がありません。

1
Steve B.

また、finalize()メソッドは一度しか呼び出されないことを知りました。私のプログラムでそれを2回呼び出した場合、内部的に何が起こっていますか?

あなたはおそらくこれをC++〜デストラクタの印象の下で尋ねます。 Java finalize()メソッドでは、メモリのクリアなどのマジックは行われません。ガベージコレクタによって呼び出されることになっています。ただし、その逆はありません。

Joshua Blochの「Effective Java」の対応する章を読むことをお勧めします。ファイナライザを使用することは悪い習慣であり、パフォーマンスやその他の問題を引き起こす可能性があると述べており、それらを使用する必要があるのはいくつかの場合のみです。この章は次の言葉で始まります。

ファイナライザは予測不可能で、多くの場合危険であり、一般に不要です。

1
Roman

finalizeが保護されている理由は、JDKの一部のクラスによってオーバーライドされ、それらのオーバーライドされたメソッドがJVMによって呼び出されたためだと思います。

1
meerut