web-dev-qa-db-ja.com

Javaでの継承を禁止する理由

Javaでの継承を禁止する正当な理由は何ですか、たとえば、最終クラスを使用するか、単一のプライベートなパラメーターなしのコンストラクターを使用するクラスを使用するなどです。メソッドを最終的にする良い理由は何ですか?

155
cretzel

ここで最も参考になるのは、ジョシュアブロッホの優れた本「Effective Java」のItem 19で、「継承または禁止するための設計と文書化」と呼ばれています。 (第2版の項目17と第1版の項目15です。)本当に読んでおくべきですが、要約します。

祖先が継承されるように設計されていない場合、継承されたクラスとその親との相互作用は驚くべきものであり、予測不可能です。

したがって、クラスには2種類あります。

  1. クラスextendedに設計されており、その方法を説明するのに十分なドキュメント

  2. クラスマーク最終

純粋に内部コードを書いている場合、これは少しやり過ぎかもしれません。ただし、クラスファイルに5文字を追加するのに必要な余分な労力は非常にわずかです。内部消費のみを記述している場合、将来のコーダーは常に「最終」を削除できます。「このクラスは継承を念頭に置いて設計されていません」という警告と考えることができます。

170
DJClayworth

オーバーライドするクラスが他のメソッドで期待される動作を変更できないように、メソッドをfinalにしたい場合があります。コンストラクタで呼び出されるメソッドはしばしばfinalと宣言されるため、オブジェクトを作成するときに不愉快な驚きを感じることはありません。

22
Bill the Lizard

クラスをfinalにする理由の1つは、継承よりも合成を強制したい場合です。これは一般に、クラス間の密結合を回避するのに望ましいものです。

17
John Topley

最終メソッドに進むことができる3つのユースケースがあります。

  1. 派生クラスが特定の基本クラス機能をオーバーライドすることを回避するため。
  2. これは、派生クラスが変更することを想定していないフレームワークのいくつかの重要なコア機能を基本クラスが提供するセキュリティ目的のためです。
  3. 最終メソッドはインスタンスメソッドよりも高速です。これは、最終メソッドとプライベートメソッドに仮想テーブルの概念を使用しないためです。そのため、可能性がある場合は、最終的な方法を使用してください。

クラスをfinalにするための目的:

そのため、これらのクラスを拡張してその動作を変更できる本体はありません。

例:ラッパークラスIntegerは最終クラスです。そのクラスが最終クラスでない場合、誰でも整数を自分のクラスに拡張し、整数クラスの基本的な動作を変更できます。これを避けるために、Javaはすべてのラッパークラスを最終クラスとして作成しました。

13
user1923551

不変オブジェクトを作成したい場合( http://en.wikipedia.org/wiki/Immutable_object )、シングルトンを作成したい場合があります( http://en.wikipedia。 org/wiki/Singleton_pattern )、または効率、安全性、またはセキュリティ上の理由で、誰かがメソッドをオーバーライドできないようにすることができます。

12
Ray Tayek

継承はチェーンソーのようなものです-非常に強力ですが、間違った手ではひどいです。継承するクラスを設計する(柔軟性が制限され、時間がかかる)か、禁止する必要があります。

Effective Java 2nd edition items 16 and 17、または私のブログ投稿 "相続税" を参照してください。

6
Jon Skeet

うーん...私は2つのことを考えることができます:

特定のセキュリティ問題を扱うクラスがあるかもしれません。サブクラス化してシステムにサブクラス化されたバージョンを供給することにより、攻撃者はセキュリティ制限を回避できます。例えば。アプリケーションはプラグインをサポートする場合があり、プラグインがセキュリティ関連のクラスをサブクラス化できる場合、このトリックを使用してサブクラス化されたバージョンを適切に密輸できます。ただし、これはむしろアプレットなどに関してSunが対処しなければならないものであり、おそらくそのような現実的なケースではありません。

より現実的な方法は、オブジェクトが可変になるのを避けることです。例えば。文字列は不変なので、コードは安全に参照を保持できます

 String blah = someOtherString;

最初に文字列をコピーする代わりに。ただし、文字列をサブクラス化できる場合は、文字列値を変更できるメソッドを追加できます。これで、上記のように文字列をコピーするだけの場合、文字列が同じままであるというコードはもはや使用できなくなり、代わりに文字列。

4
Mecki

また、商用のクローズドソースクラスを作成している場合、特にユーザーが機能をサポートする必要があり、メソッドをオーバーライドし、それを呼び出すと不満を言う場合は、機能を後から変更できないようにする必要があります。予期しない結果。

1
DavidG

クラスおよびメソッドをfinalとしてマークすると、ランタイムが特定のオブジェクトを呼び出すために適切なクラスメソッドを検索する必要がないため、パフォーマンスがわずかに向上することがあります。非最終メソッドは仮想としてマークされているため、必要に応じて適切に拡張でき、最終メソッドはクラス内で直接リンクまたはインラインでコンパイルできます。

1
seanalltogether

人々が自分自身や他者を混乱させる可能性のあることをやめること。定義済みの定数または計算がある物理ライブラリを想像してください。最終的なキーワードを使用しないと、誰かがやって来て、決して変わらないはずの基本的な計算や定数を再定義できます。

1
Anson Smith

クラスをオーバーライドしても動作が変わらないように、メソッドをfinalにする必要があります。動作を変更できるようにするには、メソッドをパブリックにします。パブリックメソッドをオーバーライドすると、変更できます。

0