ホームページ  >  記事  >  Java  >  ジェネリックとリフレクションの使用の概要 - ジェネリック

ジェネリックとリフレクションの使用の概要 - ジェネリック

高洛峰
高洛峰オリジナル
2016-12-19 15:39:001608ブラウズ

私の意見では、JDK5.0 は間違いなく画期的なバージョンであり、このバージョンでは多くの貴重な新機能が提供され、ジェネリックスもその 1 つであり、リフレクション メカニズムも強化されています。また、バージョン 5.0 では以前のコレクション フレームワークも再構築されています。汎用サポートを追加しました。

5.0 のリリースからほぼ 10 年が経ち、この点についてはオンラインや書籍でも多くの知識が得られます。エレファントは今、第一に自分自身の経験と経験を要約するために、第二に、この側面に不慣れな子供たちに何らかの助けを与えることを願って、これらのことを書いています。
ジェネリックの最大の利点は型チェックであり、これはコレクションに特に役立ち、再利用が可能になるため、基礎となるコード設計にも非常に役立ちます。ジェネリックスを定義するには 2 つの方法があります。1 つはジェネリック クラスで、もう 1 つはジェネリック メソッドです。
では、ジェネリック医薬品とは一体何でしょうか?簡単に言うと(厳密ではないかもしれませんが)、クラスでもインターフェイスでもメソッドでも、型パラメータなどの型変数を使うことを指します。例を参照してください:
汎用クラス
use ' using 's ' using through using using'' out out out out out out of 's 「 」 スルースルースルーアウトスルーアウトスルースルースルー-- ‐‐‐‐‐ public void setT(T t) {
this.t = t }
}
T はパラメータ化された型であり、山括弧 (< >) をクラス名の後に置きます。ジェネリック クラスには、複数の型変数を定義できます。型変数は通常、大文字で表されます (この例では Person、JDK では List、Map など)。
型変数を具象クラスに置き換えることで、ジェネリック クラスをインスタンス化することができます: person person = new Person();
次のようにインスタンス化するのは間違っています: person person = new Person< ;T> (); //ERROR
ジェネリック メソッド


public T get(String key, Object params) {
SSM3 の例で MyBatisDao クラスに定義したメソッドはジェネリック メソッドです。 は型変数で、get の前の T は戻り値の型です。実際、このメソッドには型安全性の問題があります。RoleService でこのメソッドを呼び出し、戻り値の型 T を User として記述した場合、コンパイラは警告メッセージを表示しません。
しかし、これを書き換えて MyBatisDao にジェネリックスを追加すると、パブリック クラス MyBatisDao が SqlSessionDaoSupport を拡張します
その場合、User の戻り値の型でコンパイル エラーが発生します:

ロール型変数 MyBatisDao に基づいて、コンパイラは、その中で定義されている get メソッドがロール型を返す必要があると推測します。ただし、この変更後、MyBatisDao はジェネリック クラスとなり、get メソッドはジェネリック メソッドではなくなりました。では、ジェネリックメソッドに安全性チェックを行うことはできるのでしょうか?はい、ただし、ある程度のプログラミング スキルが必要です。キーは作成するジェネリック メソッドに関連しています。後述する型パラメータの制限により、ジェネリックが制限され、セキュリティ チェックの問題が解決される可能性があります。
型パラメータの制限
のような型変数で表される範囲は、場合によっては大きすぎたり、使いにくい場合があります。たとえば、java.io.Serializable インターフェイスを実装するジェネリック クラスを実装する必要がある場合、これをどのように実行すればよいでしょうか。 JDK の専門家は、この問題を解決するために「制限付きワイルドカード タイプ」と呼ばれるものを設計しました。通常、これらを上限と下限と呼びます。
上限: または
疑問符 (?) ) は無制限のワイルドカードと呼ばれ、任意の型を表すことができます。場合によっては、型変数を使用するのがあまり便利ではない場合がありますが、ワイルドカード型はこの問題をうまく解決します。
は、T が Serializable インターフェイスを実装するクラスであり、T がバインディング型 (Serializable) のサブタイプであり、T とバインディング型がインターフェイスまたはクラスになる可能性があることを意味します。 Comparable インターフェイスを実装する制限を追加したい場合は、次のように記述するだけです: Comparable インターフェイスは汎用パラメーターを受け取ることができる汎用インターフェイスであるため、この記述は少し大雑把です。複雑な状況についてはここでは説明しません。
T はそれ自身のスーパータイプとみなすことができるため、T 型変数のスーパータイプには T 自体も含まれることがわかります。
では、なぜ extends が上限で extends が下限と言われるのでしょうか?前の 2 つの説明から、extends Serializable または extends T は、型変数が Serializable のサブクラスであり、T 変数のサブタイプである必要があることを示していることは明らかです。これは、型変数の上限を制限することと同じですか?同様に、下限値の意味も理解できます。
上限と下限についてこれまで述べてきましたが、それらは何に役立つのでしょうか?そしてそれをどのように使用するか?簡単に言うと、extends で修飾された型パラメータはジェネリック オブジェクトから読み取ることができ、super で修飾された型パラメータはジェネリック オブジェクトに書き込むことができます。こんなことを言うと失神してしまう子もいるかもしれない。これは一体何を言っているのだろうか?
ジェネリックの上限と下限についての式をまとめました。 PECS は、生産者-拡張、消費者-スーパーを意味します
上記は、パラメーター化された型が生産者を表す場合、< を使用することを意味します。 T> が消費者を表す場合は、 を使用します。上記の説明と合わせて理解してみましょう。それでもよく理解できない場合は、Elephant が違いを理解するための短いコードを添付します。
public void add(List list){
for(T t : list){
} public void add(T t, List list){
List.add(t);
}
ジェネリック消去
ジェネリックは主にコンパイル中に有効です。つまり、コンパイル中に型安全性がチェックされます。現在、コードを記述するときは、一般に Eclipse または IntelliJ を使用して、これらの統合開発ツールをオンザフライでコンパイルできます。エラーがあるとすぐに赤いエラーマークが表示されます。したがって、型変換エラーが発生した場合、結果は明らかです。ただし、プログラムの実行段階では、JVM はジェネリックスがマジックであることを認識しません。ジェネリックスを含むすべてのクラス、インターフェイス、およびメソッドは、そのジェネリックスが消去され、生の型になります。つまり、Person list を拡張すると List list になります。
以下は、前の person クラスを javap で逆コンパイルした結果です。 T は非修飾型であるため、すべての型変数が消去されています。さらに、add メソッドの も削除されました。
public class com.bolo.person extends java.lang.Object{
private java.lang.Object t;
public com.bolo.Person();
public java.lang.Object getT();
public void setT(java.lang.Object);
public void add(java.util.List);
public void add(java.lang.Object);
public void add(java.lang.Object, java.util. List);
}
したがって、ジェネリック消去の機能に関しては、次の点に注意する必要があります:
1. JVM にはジェネリックはなく、通常のクラスとメソッドのみが存在します。
2. すべての型パラメータは、オブジェクトを使用して制限された型または無制限の型に置き換えられます。
3. メソッドのオーバーロードは注意して扱ってください。オーバーロードを誤って使用すると、目的の多態性が実現されません。
4. 型の安全性を確保するため、必要に応じて強制型変換を使用してください。
ジェネリックの制限
基本型は型パラメータとして使用できません。 person は間違っています。使用できるのは person のみです。 型チェックではプリミティブ型のみを使用できます。 if(t instanceof Person) if(t instanceof Person)と書くと即コンパイルエラーになります
型変数はインスタンス化できません。これを書くのは間違いです: T t = new T()
パラメータ化された型の配列をインスタンス化することはできません。 Person[] p = new Person[5] //エラー
静的インスタンス変数と静的メソッドは定義できません。次のように書きたい場合: private static T a その場合、申し訳ありませんが、コンパイラはすぐにエラー メッセージを表示します。
実際、ジェネリックの制限について話す必要はありません。これを実行すると、すぐにエラーが表示されます。
最後に、ジェネリックはコレクションに最も役立ちます。コレクションはコンテナであり、ジェネリックを使用すると再利用が容易になります。最も頻繁に使用するコレクションは List であり、もう 1 つのコンテナーは配列です。Elephant では、List をより使用し、配列は使用しないことを強くお勧めします。 1 つ目は List に型安全性チェックがあること、2 つ目は List が配列のすべての関数を提供し、より豊富であること、3 つ目は List が gc を最適化することです。配列を使用する場合、特にオブジェクト配列を操作する場合、経験が浅く配列内のオブジェクト参照を解放しないと、メモリ リークが発生しやすくなります。




ジェネリックの使用法とリフレクションの概要に関連するより一般的な記事については、PHP 中国語 Web サイトに注目してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。