ホームページ  >  記事  >  Java  >  Java -- ジェネリックス

Java -- ジェネリックス

巴扎黑
巴扎黑オリジナル
2017-06-27 09:13:571865ブラウズ

型パラメータ

ジェネリック クラスを定義する場合、または ジェネリック クラスの変数を宣言する場合、山括弧を使用して仮型パラメータを指定します。仮型パラメーターと実際の型パラメーターの関係は、型パラメーターが値ではなく型を表すことを除いて、仮メソッド パラメーターと実際のメソッド パラメーターの関係に似ています。

名前付き型パラメーター

推奨される命名規則は、型パラメーターには大文字の 1 文字の名前を使用することです。これは C++ の規則 (付録 A: C++ テンプレートとの比較を参照) とは異なり、ほとんどの generic クラスが少数の型パラメーターを持つという仮定を反映しています。一般的な ジェネリック パターンの場合、推奨される名前は次のとおりです:

K - キー (マップされたキーなど)。
V —— List や Set の内容、または Map 内の値などの値。
E——例外クラス。
T —— 一般的

方法签名由方法名称和一个参数列表(方法的参数的顺序和类型)组成。

1. ジェネリックスを使用する理由

1. 入れることができる要素に制限はありません。2 つの異なるオブジェクトを入れると例外が発生する可能性があります。

2. オブジェクトをコレクションに投げます。コレクションはオブジェクトを保持していることだけを知っているため、通常はコレクション要素を取り出した後、強制変換を実行する必要があります。

2 .ジェネリックとは何ですか

Javaのパラメータ化された型はジェネリックと呼ばれ、コレクションを作成するときにプログラムがコレクション要素の型を指定できるようにします

3. ダイヤモンド構文ジェネリックスの

必要なのはその後にダイヤモンド括弧のペアだけです。ジェネリックスを持ってくる必要はありません

4. ジェネリック宣言を使用してカスタム クラスを作成します。 class、construct デバイス名は元のクラス名のままなので、ジェネリック宣言を追加しないでください。

5. ジェネリック クラスからサブクラスを派生する場合、継承時に親クラスの実際のパラメータを渡す必要があります

public class A extends Applef7e83be87db5cd2d9a8a0b8117b38cd4{}

親クラスをオーバーライドするすべてのメソッドは、対応する型になります

実際のパラメータを渡さないこともできます

public class A extends Apple{}

オブジェクト型として

6. ジェネリック クラスはありません

ジェネリックの実際の型パラメータが何であっても、実行時には常に同じクラスを持ちます。どのタイプの実パラメータがジェネリックの type パラメータに渡されるかに関係なく、( は Java のジェネリックの概念の目的にあり、そのため、ジェネリックはコードのコンパイル フェーズでのみ機能します。コンパイル プロセス中に、ジェネリックを正しくチェックする必要があります。型の結果の後、ジェネリック情報は消去されます。つまり、正常にコンパイルされたクラス ファイルにはジェネリック情報が含まれません。Java の実行フェーズには入りません )。一般に、これらは同じクラスとして扱われ、メモリ内のメモリ空間を占有するため、静的メソッド、静的初期化ブロック、または静的変数の宣言と初期化では型パラメータを使用することはできません

説明:

静的変数は、ジェネリック クラスのすべてのインスタンスによって共有されます。 MyClass8742468051c85b06f0a0af9e3e506b5c として宣言されたクラスの場合、そのクラス内の静的変数にアクセスするメソッドは依然として MyClass.myStaticVar です。オブジェクトが new MyClassf7e83be87db5cd2d9a8a0b8117b38cd4 または new MyClassc0f559cc8d56b43654fcbe4aa9df7b4a のどちらによって作成されたかに関係なく、それらはすべて静的変数を共有します。型パラメーターが静的変数の型として許可されると仮定します。次に、次の状況を考えてみましょう。

MyClassc0f559cc8d56b43654fcbe4aa9df7b4a クラス 2 = new MyClassc0f559cc8d56b43654fcbe4aa9df7b4a();

class1.myStaticVar = "hello";

class2.myStaticVar = 5;

ジェネリックシステムによるタイプ消去。 myStaticVar が Object 型に復元され、その後 class1.myStaticVar= "hello"; が呼び出されると、コンパイラは強制的な型変換を実行します。つまり、myStaticVar = (String)"hello"; が実行されると、呼び出されると、コンパイラは強制的な型変換を実行し続けます。 , myStaticVar = (Integer)Integer.valueOf(5); この時点では、当然、このステートメントは実行時に ClassCastException をスローします。タイプの安全性の問題。したがって、ジェネリック システムでは、クラスの静的変数が型パラメーターを変数の型として使用することはできません。

ジェネリック クラスは実際にはシステム内で生成されないため、インスタンスOD 演算子の後にはジェネリック クラスがまったく存在しないため、使用できません。

7. ワイルドカードを入力します Foo が Bar のサブタイプであり、G がジェネリック宣言を持つクラスまたはインターフェイスである場合、G4ee996100bf04ab273e687539c860625 は Gad40e550a33cb99ea30eede96e03e60e ではないことに注意してください。 。

Lista87fdacec66f0909fc0757c19f2d2b1d が論理的に Listf7e83be87db5cd2d9a8a0b8117b38cd4 の親クラスとみなせると仮定すると、a.test(list) にはエラー プロンプトが表示されず、getData( によって問題が発生します。 ) メソッドがデータを取得するときの型は何ですか?整数か、それともオブジェクトか?また、プログラミングの順序は制御できないため、必要に応じて型判定や強制的な型変換を行う必要があります。明らかに、これはジェネリックの概念と矛盾します。したがって、論理的には、Lista87fdacec66f0909fc0757c19f2d2b1dListf7e83be87db5cd2d9a8a0b8117b38cd4

の親クラスと見なすことはできません。ジェネリック コレクションの親クラスは、型ワイルドカードを使用できます。型ワイルドカードは、任意の型に一致する疑問符です。 型ワイルドカードは、通常、特定の型引数の代わりに ? を使用します。ここにあるのは型パラメータではなく、実際の型パラメータであることに注意してください。そして List6b3d0130bba23ae47fe2b8e8cddf0195 は論理的に Listc0f559cc8d56b43654fcbe4aa9df7b4a、Listfbc66dd936c67ec24b25b8c2fe0a2883... およびすべての List8e4a42b25090f2d9d55ce057d46e5cc5 の親クラスです。これからも、そのような要件を満たす汎用メソッドを定義できます。

リストの実際の型が何であっても、それには Object が含まれます注: ワイルドカードは、それがさまざまなジェネリック コレクションの親クラスであることを意味するだけであり、それに要素を追加することはできません

C コレクション内の要素の型が不明なため、オブジェクトを追加できません

7.1 ワイルドカードの上限を設定します

Listc13078eef089064b7e80988f58350b9c が List< ではないため;Shape>son 型のため、コンパイルエラー

このリサイクルでは、制限された汎用ワイルドカードを使用できます

7.2 型パラメータの上限を設定します

8。一般的なメソッド

メソッドを定義するときは、マルチスレッドを考慮せずに、同時に

の型パラメータを使用しません。は初期化されて一度呼び出されるため、重複した初期化や不正な呼び出しは発生せず、データベース内のダーティなデータを読み取るような状況も発生しないため、強制的な型変換でコード エラーが発生することはありません。

メソッド宣言で定義された仮パラメータは、このメソッド内でのみ使用できます。

クラスやインターフェイスとは異なり、メソッドのジェネリックスは渡される実際の型パラメータを示す必要はありません

どの型を渡すかについてコンパイラが混乱しないようにしてください

たとえば、test

String 型または Object 型を渡します。コンパイラは T を 5896f08235467053ee8e2a673bd83d91 a, Collection を使用すると、クラスをジェネリック化できます。メソッドが定義されているクラスがジェネリックであるかどうかに関係なく、メソッドをジェネリック化することもできます。

ジェネリック クラスは、複数のメソッド シグネチャにわたって型制約を強制します。 Listd94943c0b4933ad8cac500132f64757f では、型パラメータ V が get()、add()、contains() などのメソッドのシグネチャに現れます。 Map 型の変数を作成するときは、メソッド間の型制約を宣言します。 add() に渡す値は、get() によって返される値と同じ型になります。

同様に、ジェネリック メソッドを宣言する理由は、通常、メソッドの複数のパラメーター間の型制約を宣言するためです。たとえば、次のコードの ifThenElse() メソッドは、最初のパラメータのブール値に応じて 2 番目または 3 番目のパラメータを返します。 T Second) {

return b ? first : Second;

}

T の値を明示的に指定せずに ifThenElse() を呼び出すことができることに注意してください。コンパイラは、T がどのような値を持つかを明示的に伝える必要はありません。値がすべて同じでなければならないことだけを知っています。コンパイラでは、型推論を使用して、T に置換された String がすべての型制約を満たしていると推定できるため、次のコードを呼び出すことができます。 ;

同様に、次のように呼び出すことができます:

Integer i = ifThenElse(b, new Integer(1), new Integer(2));

ただし、必要な型制約を満たす型がないため、コンパイラーは次のコードを許可しません。

String s = ifThenElse(b, "pi", new Float(3.14));

型 T をクラス定義に追加する代わりに、ジェネリック メソッドを使用することを選択したのはなぜですか?これを行う必要があるケースは (少なくとも) 2 つあります:

ジェネリック メソッドが静的である場合、この場合クラス型パラメーターは使用できません。

T の型制約がメソッドに対して真にローカルである場合、同じクラスの別のメソッド シグネチャで使用されている同じ型 T には制約が存在しないことを意味します。閉じた型のシグネチャは、ジェネリック メソッドの型パラメーターをメソッドに対してローカルにすることで簡素化できます。


制限された型

前の画面のジェネリックメソッドの例では、型パラメーター V は制約なしまたは制約なしの型です。型パラメーターが完全に指定されていない場合、型パラメーターに追加の制約を指定することが必要になる場合があります。

Number クラスによって制限される型パラメーター V を使用する Matrix クラスの例を考えてみましょう。 コンパイラでは、Matrixc0f559cc8d56b43654fcbe4aa9df7b4a 型または Matrix8dd2730a9d553ba0024e58b921fa6ad1 型の変数を作成できますが、Matrixf7e83be87db5cd2d9a8a0b8117b38cd4 型の変数を定義しようとすると、エラーが発生します。型パラメーター V は、 Number によって制限されるように評価されます。型の制限がない場合、型パラメーターはオブジェクトによって制限されているとみなされます。前の画面の例「ジェネリック メソッド」では、コンパイラが型パラメーター V の型を認識していなくても、List6b3d0130bba23ae47fe2b8e8cddf0195 で呼び出されたときに List.get() が Object を返すことができるのはこのためです。

9. ジェネリックメソッドと型ワイルドカードの違い

仮パラメータ (a) の型またはメソッドの戻り値の型が別の仮パラメータ ( b) type の場合、仮パラメータ (b) の型宣言ではワイルドカードを使用しないでください。メソッド シグネチャで宣言された型パラメータ、つまりジェネリック メソッドのみが考慮されます。

私が理解しているのは、型ワイルドカードはコレクション内の要素を追加または変更する必要がなく、型ワイルドカードを使用すると、他の要素に付加されるのではなく、他の要素に付加されるということです。メソッド シグネチャは、変数の型を定義するためにも使用できます。ジェネリック メソッドの型パラメーターは、対応するメソッドで明示的に宣言する必要があります。

10. 消去と変換

ジェネリック情報を持つオブジェクトをジェネリック情報のない別の変数に代入する場合、山かっこ内のすべての型情報が破棄されます。

li を List に代入すると、コンパイラーは前者の汎用情報を消去します。つまり、リスト コレクション内の要素の型情報が失われます。

Java では、リスト オブジェクトを List30690cee1a11d5dfbdced93b89f678ee 変数に直接割り当てることもできるため、プログラムをコンパイルして渡すことはできますが、発行されるのは 「未チェック変換」 (論理親クラスを子クラスに直接割り当てる) だけです。 ただし、list 変数は実際には listc0f559cc8d56b43654fcbe4aa9df7b4a コレクションを参照しているため、コレクション内の要素を String 型オブジェクトとして取り出そうとすると、実行時例外がスローされます

11。

Java ジェネリックには非常に重要な設計原則があります。コードの一部がコンパイル時に「未変換の例外」警告を生成しない場合、プログラムはすべての配列要素の型で ClassCastException 例外を引き起こしません。無制限の型ワイルドカードでない限り、型変数または型パラメーターを含めることはできませんが、型変数または型パラメーターの配列を含むように要素の型を宣言することはできます

それが合格すると仮定すると、警告は発生しませんが、例外がスローされます

次の形式に変更します:

最初の行には「未チェックの変換」警告が表示され、最後の行にも例外がスローされます

キャップなしのワイルドカード ジェネリック 配列

はコンパイル時に警告を発行しませんが、プログラムは lsa の最初の配列要素の最初のコレクション要素を String 型に強制する必要があるため、実行時に例外がスローされます。プログラムは、データ型を保証するために、instanceof 演算子を渡す必要があります

同様に、要素の型が型変数である配列オブジェクトを作成すると、コンパイル エラーが発生します

8742468051c85b06f0a0af9e3e506b5c T[] makeArray(Collection8742468051c85b06f0a0af9e3e506b5c ; coll)

{ return new T[cool.size()]

}

型変数は実行時に存在せず、コンパイラーは実際の型を判断できません

以上がJava -- ジェネリックスの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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