3

Saw a couple of similar questions today- got me thinking:

What are the rules for when to use generics?

  • When a collection is involved?
  • When there are getter methods which return collection elements?
  • Whether the object changes type during its lifetime?
  • Whether the relationship is composition/aggregation to the class?

There doesn't seem to be a consensus on the questions you should ask yourself in order to determine whether you should use generics. Is it purely an opinionated decision?

Is it easier to ask when you shouldn't use generics??

4

4 に答える 4

4

箇条書きの最初のポイントに戻る前に、ジェネリックと型情報に関する一般的なポイントから始めましょう。


ジェネリックは不要な型キャストを防ぎます。

ジェネリックが導入される前の Java を覚えていますか? 型キャストはいたるところで使用されていました。

これが型キャストの本質です。コンパイラはオブジェクトの型を認識していないか、推測できないため、オブジェクトの型についてコンパイラに伝えています。

型キャストの問題は、時々間違いを犯すことです。クラスのインスタンスが ( ) であることをコンパイラーに提案できますFiddleFrobbleコンパイラー(Frobble)fiddleは喜んであなたを信じて、ソース コードをコンパイルします。しかし、それが間違っていたことが判明した場合は、後でかなりの実行時エラーが発生します。

ジェネリックは、コンパイラに型情報を保持させる別の方法であり、通常はより安全な方法です。基本的に、コンパイラーは人間のプログラマーよりもタイプミスをする可能性が低くなります...必要なタイプキャストが少ないほど、潜在的なエラーソースが少なくなります! Fiddleリストにオブジェクト ( )のみを含めることができることを確立するとList<Fiddle>、コンパイラはこの情報を保持し、そのリスト内の各項目を何らかの型に型キャストする必要がないようにします。(リスト項目を にキャストすることはできFrobbleますが、コンパイラがその項目が !? であることを知らせるようになったので、キャストする必要があるのはなぜFiddleですか?)

ジェネリックを使用すると、型キャストの必要性が大幅に減少することがわかったので、多くの型キャストが存在する場合 (特に常に同じ型にキャストする場合) は、代わりにジェネリックを使用する必要があることを示している可能性があります。

コンパイラができるだけ多くの型情報を保持できるようにすることは良いことです。なぜなら、型エラーは早期に(実行時ではなくコンパイル時に)発見できるからです。

「ジェネリック」java.lang.Objectタイプの代替としてのジェネリック:

ジェネリックが登場する前は、あらゆる型で動作するメソッドを書きたい場合はjava.lang.Object、すべてのクラスがスーパータイプから派生しているため、スーパータイプを使用していました。

ジェネリックを使用すると、任意の型に対して機能するメソッドを作成することもできますが、既知の型情報を強制的に破棄する必要はありません。これは、オブジェクトを型にキャストするときに発生することとまったく同じですObject。したがって、Object型が頻繁に使用されることは、ジェネリック適切である可能性を示すもう 1 つの指標となる可能性があります。


コレクションが関係するのはいつですか?

ジェネリックがコレクションに特に適していると思われるのはなぜですか? 上記の理由によると、コレクションにあらゆる種類のオブジェクトを含めることはめったに許可されないためです。もしそうならObject、コレクションに何の制限も課さないので、型は適切でしょう。ただし、通常、コレクション内のすべてのアイテムは (少なくとも) a Frobble(またはその他の型) であると予想され、コンパイラに知らせると役立ちます。ジェネリックはまさに​​それを行う方法です。


その関係はクラスへの合成/集約か?

プロパティを持つことを尋ねる別の質問にリンクしましたとしてジェネリックにする必要があります。class Personcarclass Person<T extends ICar>

その場合、プログラムで Honda と Opel を区別する必要があるかどうかによって異なります。このようなPersonクラスをジェネリックにすることで、本質的にさまざまな種類の人々の可能性を導入できます。これで実際にコードの問題が解決する場合は、それを実行してください。ただし、それがハードルと困難をもたらすだけの場合は、衝動に抵抗し、非ジェネリックPersonクラスにとどまります。

サイド ノード: クラス全体をジェネリックにする必要はないことに注意してください。いくつかの特定のメソッドのみをジェネリックにすることができます。少なくとも .NET エコシステムでは、ジェネリックを可能な限り「ローカル」に保つことをお勧めします。つまり、メソッドをジェネリックにするだけで十分な場合は、クラスをジェネリックに変換しないでください。

于 2012-07-11T20:07:40.147 に答える
2

次の 3 つの基準が満たされている場合、ジェネリックを使用していることに気づきます。

  1. コードを繰り返していることに気づき、それを新しいメソッド/クラスにリファクタリングする方法を考え始めました。
  2. 私が書き直しているクラス/メソッドは、引数の 1 つの具象型が何であるかを実際には気にせず、特定の契約に従うことだけを気にします (例: <T extends Bar>)。
  3. メソッドの戻り値の型/メソッドの1つが上記のパラメーターに関連しているか、
    2つ以上のパラメーターが関連しており、同じ型である必要がありますが、その型が何であるかはあまり気にしません。

通常、これらの基準が満たされている場合、Collection何らかの関係がありますが、必ずしもそうとは限りません。

于 2012-07-11T20:00:20.803 に答える
0

私の意見では、2 番目のステートメント (使用しない場合) は正しいです。

ジェネリックを使用しない場合: 厳密な型指定が制限的すぎる場合 (通常、ジェネリック内のジェネリック)。場合によっては、コンポーネント間の疎結合を確実にしたい場合があります。要点は、「必要なものを送ってください。API が何らかの方法でそれを処理します」ということです。汎用型を使用して完全な具体的な API を指定するのではなく、ある種のビジターを使用します。 .

必要な場合: そうでない場合は、変数を何らかの型にキャストする必要があります (instanceof を推測または使用する必要がある場合もあります)...


補足: すべての構造化型は何らかのコレクションです...

于 2012-07-11T20:04:59.003 に答える