箇条書きの最初のポイントに戻る前に、ジェネリックと型情報に関する一般的なポイントから始めましょう。
ジェネリックは不要な型キャストを防ぎます。
ジェネリックが導入される前の Java を覚えていますか? 型キャストはいたるところで使用されていました。
これが型キャストの本質です。コンパイラはオブジェクトの型を認識していないか、推測できないため、オブジェクトの型についてコンパイラに伝えています。
型キャストの問題は、時々間違いを犯すことです。クラスのインスタンスが ( ) であることをコンパイラーに提案できますFiddle
。Frobble
コンパイラー(Frobble)fiddle
は喜んであなたを信じて、ソース コードをコンパイルします。しかし、それが間違っていたことが判明した場合は、後でかなりの実行時エラーが発生します。
ジェネリックは、コンパイラに型情報を保持させる別の方法であり、通常はより安全な方法です。基本的に、コンパイラーは人間のプログラマーよりもタイプミスをする可能性が低くなります...必要なタイプキャストが少ないほど、潜在的なエラーソースが少なくなります! Fiddle
リストにオブジェクト ( )のみを含めることができることを確立するとList<Fiddle>
、コンパイラはこの情報を保持し、そのリスト内の各項目を何らかの型に型キャストする必要がないようにします。(リスト項目を にキャストすることはできFrobble
ますが、コンパイラがその項目が !? であることを知らせるようになったので、キャストする必要があるのはなぜFiddle
ですか?)
ジェネリックを使用すると、型キャストの必要性が大幅に減少することがわかったので、多くの型キャストが存在する場合 (特に常に同じ型にキャストする場合) は、代わりにジェネリックを使用する必要があることを示している可能性があります。
コンパイラができるだけ多くの型情報を保持できるようにすることは良いことです。なぜなら、型エラーは早期に(実行時ではなくコンパイル時に)発見できるからです。
「ジェネリック」java.lang.Object
タイプの代替としてのジェネリック:
ジェネリックが登場する前は、あらゆる型で動作するメソッドを書きたい場合はjava.lang.Object
、すべてのクラスがスーパータイプから派生しているため、スーパータイプを使用していました。
ジェネリックを使用すると、任意の型に対して機能するメソッドを作成することもできますが、既知の型情報を強制的に破棄する必要はありません。これは、オブジェクトを型にキャストするときに発生することとまったく同じですObject
。したがって、Object
型が頻繁に使用されることは、ジェネリックが適切である可能性を示すもう 1 つの指標となる可能性があります。
コレクションが関係するのはいつですか?
ジェネリックがコレクションに特に適していると思われるのはなぜですか? 上記の理由によると、コレクションにあらゆる種類のオブジェクトを含めることはめったに許可されないためです。もしそうならObject
、コレクションに何の制限も課さないので、型は適切でしょう。ただし、通常、コレクション内のすべてのアイテムは (少なくとも) a Frobble
(またはその他の型) であると予想され、コンパイラに知らせると役立ちます。ジェネリックはまさにそれを行う方法です。
その関係はクラスへの合成/集約か?
プロパティを持つことを尋ねる別の質問にリンクしましたとしてジェネリックにする必要があります。class Person
car
class Person<T extends ICar>
その場合、プログラムで Honda と Opel を区別する必要があるかどうかによって異なります。このようなPerson
クラスをジェネリックにすることで、本質的にさまざまな種類の人々の可能性を導入できます。これで実際にコードの問題が解決する場合は、それを実行してください。ただし、それがハードルと困難をもたらすだけの場合は、衝動に抵抗し、非ジェネリックPerson
クラスにとどまります。
サイド ノード: クラス全体をジェネリックにする必要はないことに注意してください。いくつかの特定のメソッドのみをジェネリックにすることができます。少なくとも .NET エコシステムでは、ジェネリックを可能な限り「ローカル」に保つことをお勧めします。つまり、メソッドをジェネリックにするだけで十分な場合は、クラスをジェネリックに変換しないでください。