ジェネリック
コレクションの要素を特定のタイプに制限します。
用語
いくつかのメモ:
パラメーター化されたタイプとプリミティブタイプは互いに互換性があります
ArrayList Collection1 = new ArrayList <Integer>(); // pass、no warningArraylist <integer> collection2 = new arrayList(); // pass、警告があります
パラメーター化されたタイプは、型パラメーターの継承関係を考慮していません
ArrayList <String> collection3 = new ArrayList <Object>(); //コンパイルは渡されませんarrayList <object> collection4 = new arraylist <string>(); //コンパイルは渡されません
しかし
ArrayList Collection5 = new ArrayList <Integer>(); arrayList <String> collection6 = collection5; // compiled by
「?」ワイルドカード
「?」あらゆるタイプを意味します。 「?」を使用しますさまざまなパラメーター化されたタイプを参照するワイルドカード文字。パラメーター化(size()メソッドなど)に関連していないメソッドを呼び出すことができ、パラメーター化(add()メソッドなど)に関連するメソッドを呼び出すことはできません。
ワイルドカードエクステンション
ワイルドカード文字の上限を修飾します
arrayList <?番号> collection1 = new arrayList <integer>(); // arrayList <?番号> collection2 = new ArrayList <String>(); // notによってコンパイルします
ワイルドカード文字の下限を修飾します
arrayList <? super integer> collection3 = new arrayList <number>(); // arrayList <? super integer> collection4 = new ArrayList <String>(); // notによってコンパイル
カスタムジェネリックメソッド
C ++テンプレート関数
テンプレート<class t> t add(t x、t y){return(t)(x+y);}Java Genericsは基本的にコンパイラに完全に実装されており、コンパイラがタイプチェックとタイプ判断を実行し、通常の非遺伝子バイトコードを生成するために使用します。この実装手法は「消去」です。
「消去」インスタンス
ジェネリックはJavacコンパイラに提供され、コレクションの入力タイプを定義します。コンパイラがタイプの説明でコレクションをコンパイルすると、「タイプ」情報が削除されます。
public class generictest {public static void main(string [] args){new generictest()。testtype(); } public void testType(){arrayList <integer> collection1 = new arrayList <Integer>(); arrayList <string> collection2 = new ArrayList <String>(); system.out.println(collection1.getClass()== collection2.getClass()); // 2つのクラスタイプは同じです。つまり、bytecodeは同じsystem.out.println(collection2.getClass()。getName()); //クラスはjava.util.arraylistであり、実際のタイプパラメーター情報はありません}}出力
真実
java.util.arraylist
リフレクションを使用してコンパイラをスキップし、他のタイプのデータを一般的なコレクションに追加します。
一般的な方法の実際のパラメーターとして使用できます。
public class generictest {public static void main(string [] args){swap(new String [] {"111"、 "222"}、0,1); // compile by // swap(new int [] {1,2}、0,1); // intが参照型スワップではないためコンパイルしないでコンパイルします(new integer [] {1,2}、0,1); //コンパイル}/*配列a*/public static <t> void swap(t [] a、int i、int j){t temp = a [i]; a [i] = a [j]; a [j] = temp; }}ただし、自動パッキングとアンボクシングがあるため、基本的なタイプは実際のパラメーターとして使用できる場合があることに注意してください。例(コンパイルされて渡された):
public class generictest {public static void main(string [] args){new generictest()。testtype(); int a = biggerone(3,5); // int and double、数字番号b = biggerone(3,5.5)としてインターチェンジを取得します。 // string and intオブジェクトとしてインターチェンジを取得しますc = biggerone( "1"、2); } // x、y public static <t> t biggerone(t x、t y)からyを返す{return y; }}同時に、この例は、実際のパラメーターが一貫していない場合、Tが交差点、つまり最初の一般的な親クラスを取ることも示しています。さらに、数字b = biggerone(3,5.5)を使用する場合。ひもc = biggerone(3,5.5);次に、コンパイルエラーが報告されます。
エラー:(17、29)Java:互換性のないタイプ:推測されたタイプは、上限の推論を満たしていません:java.lang.number&java.lang.comparable <? java.lang.number&java.lang.comparable <?>>を拡張します
上限:java.lang.string、java.lang.object
しかし、私が理解していないことが1つあります。 IDEAでステップバイステップのデバッグを作成しましたが、結果は次のとおりです。一般的なデバッグスクリーンショット-1 bがタイプダブルである理由がわかりません(ただし、ダブルBで返される値を受信するときにエラーをコンパイルして報告します)。 IDEと関係があるかどうかはわかりません。 IDEは、デバッグ時にこのオブジェクトの最も正確なタイプを表示しますか?
型パラメーターのタイプ推論
コンパイラが一般的な方法の実際のタイプパラメーターを判断するプロセスは、タイプ推論と呼ばれます。
特定のタイプ変数がすべてのパラメーターの1つのみとパラメーターリスト全体の値を返す値のみを適用する場合、メソッドが呼び出されたときの実際のアプリケーションタイプに基づいて決定されます。つまり、一般的なパラメーターのタイプは、メソッドが呼び出されたときに渡されたパラメータータイプまたは返信値に基づいて直接決定されます。例えば:
スワップ(新しい文字列[3]、1,2) - > static <e> void swap(e [] a、int i、int j)
タイプ変数がすべてのパラメーターの複数の場所で適用され、パラメーターリスト全体の値を返す場合、多くの実際のアプリケーションタイプがメソッドを呼び出すときに同じタイプに対応する場合、汎用パラメーターのタイプはそのタイプです。例えば:
追加(3,5) - > static <t> t add(t a、t b)
特定のタイプ変数がすべてのパラメーターの多くの場所で適用され、パラメーターリスト全体の値を返す場合、非常に多くの場所の実際のアプリケーションタイプが、メソッドを呼び出すときに異なる型に対応し、戻り値がない場合、複数のパラメーター、つまり最初の一般的な親クラスの最大交差点タイプ。例えば:
fill(new Integer [3]、3.5) - > static <t> void fill(t a []、t v)
この例の実際の対応するタイプは、数字、コンパイル、実行の問題です。
すべてのパラメーターの複数の場所でタイプ変数が適用され、パラメーターリスト全体の返品値が適用される場合、メソッドを呼び出すときに多くの場所の実際のアプリケーションタイプが異なる型に対応し、返品値がある場合、返品値のタイプが優先されます。たとえば
int x = add(3,3.5) - > static <t> t add(t a、t b)
上記の例をまとめたエラーをコンパイルし、Xタイプがフロートに変更され、エラーも報告され、数の変更が成功しました。
パラメータータイプの型推論の例は推移的です。
copy(new Integer [5]、new String [5]) - > static <t> void copy(t [] a、t [] b)
この例は、実際のパラメータータイプがオブジェクトであり、コンパイルされていることを推測します。
copy(new arraylist <string>、new Integer [5]) - > static <t> void copy(collection <t> a、t [] b)
この例は、パラメーター化されたArrayListクラスインスタンスに基づいて、型変数を文字列型として直接決定し、コンパイルのエラーを報告します。
カスタムジェネリッククラス
例
public class genericdao <t> {public void add(t x){} public t findbyid(int id){return null; } public void delete(t obj){} public void delete(int id){} public void update(t obj){} public t findbyusername(string name){return null; } public <t> set <t> findByConditions(string where){return null; }}注:変数がジェネリックとして宣言されている場合、インスタンス変数とメソッド(および組み込み型)でのみ呼び出すことができますが、静的変数と静的メソッドによっては呼ばれません。静的メンバーはパラメーター化されたクラスで共有されるため、静的メンバーはクラスレベルのタイプパラメーターを持たないはずです。
一般的な方法と一般的なクラスの比較
例:
public class a <t>(){//汎用クラスのメンバーメソッド、tはpublic t memberfunc(){return null; } //ジェネリックメソッド、ここでは、tとtはクラスA public static <t> t genericfunc(t a)のtのtとは異なります{return null; } public static void main(string [] args){//コンパイルなしでコンパイルされた// integer i = a <string>()。findbyusername( "s"); // set <integer> set = a <string>()。findbyconditions( "s"); }}ここでは、integer i = a <string>()。findbyUsername( "s");エラーをコンパイルして報告します。
エラー:(35、61)Java:互換性のないタイプ:java.lang.stringはjava.lang.integerに変換できません
この例から、一般的な方法のtとクラスAのtが異なることがわかります。
ジェネリックと反射
反射を通してジェネリックの実際のタイプパラメーターを取得する
メソッドのパラメーターとして汎用変数を使用し、メソッドクラスのgetGenericParametertypesメソッドを使用して、ジェネリックの実際の型パラメーター例を取得します。
public class generictest {public static void main(string [] args)throws exception {getParamtype(); } /*反射を使用して、メソッドパラメーターの実際のパラメータータイプを取得します* / public static void getParamtype()throws nosuchmethodexception {method method = generictest.class.getMethod( "ApplyMap"、map.class); //メソッドタイプの一般的なパラメーターのタイプを取得します[]型= method.getGenericParametertypes(); System.out.println(types [0]); // parameterized type parameterizedType ptype =(parameterizedType)型[0]; // Primitive Type System.out.println(ptype.getRawType()); //実際の型パラメーターsystem.out.println(ptype.getActualTypearguments()[0]); System.out.println(ptype.getActualTypearguments()[1]); } /*パラメータータイプをテストする方法* / public static void applymap(map <integer、string> map){}}出力結果:
java.util.map <java.lang.integer、java.lang.string>インターフェイスjava.util.mapclass java.lang.integerclass java.lang.string