私たちが知っているのは、「任意のクラスのすべてのインスタンスが、そのタイプのクラスの同じjava.lang.Classオブジェクトを共有している」ということだけです。
例えば)
Student a = new Student();
Student b = new Student();
その後a.getClass() == b.getClass()
、本当です。
今仮定します
Teacher t = new Teacher();
ジェネリックなしでは以下が可能です。
Class studentClassRef = t.getClass();
しかし、これは今間違っています..?
例)public void printStudentClassInfo(Class studentClassRef) {}
で呼び出すことができますTeacher.class
これはジェネリックを使用して回避できます。
Class<Student> studentClassRef = t.getClass(); //Compilation error.
Tとは何ですか?Tは型パラメーター(型変数とも呼ばれます)です。山かっこ(<>)で区切られ、クラス名の後に続きます。
Tは単なる記号であり、クラスファイルの書き込み中に宣言された変数名(任意の名前)と同様です。その後、Tは
初期化中に有効なクラス名に置き換えられます(HashMap<String> map = new HashMap<String>();
)
例えば) class name<T1, T2, ..., Tn>
したがってClass<T>
、特定のクラスタイプ ' T
'のクラスオブジェクトを表します。
クラスメソッドが以下のような不明な型パラメーターで機能する必要があると仮定します
/**
* Generic version of the Car class.
* @param <T> the type of the value
*/
public class Car<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
ここでは、T String
をCarNameとしてタイプとして使用できます。
OR Tは、Integer
typeとしてmodelNumberとして使用できます。
OR TはObject
、有効な車のインスタンスとしてタイプとして使用できます。
ここで、上記は実行時に別の方法で使用できる単純なPOJOです。
コレクション例)リスト、セット、ハッシュマップは、Tの宣言に従ってさまざまなオブジェクトで機能する最良の例ですが、Tを文字列として宣言
すると、
例)HashMap<String> map = new HashMap<String>();
それは文字列クラスインスタンスオブジェクトのみを受け入れます。
ジェネリックメソッド
ジェネリックメソッドは、独自の型パラメーターを導入するメソッドです。これはジェネリック型の宣言と似ていますが、型パラメーターのスコープは、それが宣言されているメソッドに限定されます。静的および非静的なジェネリックメソッド、およびジェネリッククラスコンストラクターを使用できます。
ジェネリックメソッドの構文には、山かっこで囲まれた型パラメーターが含まれ、メソッドの戻り型の前に表示されます。ジェネリックメソッドの場合、型パラメーターセクションは、メソッドの戻り型の前に指定する必要があります。
class Util {
// Generic static method
public static <K, V, Z, Y> boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
class Pair<K, V> {
private K key;
private V value;
}
<K, V, Z, Y>
メソッドの引数で使用される型の宣言は、ここにある戻り型の前にありboolean
ます。
以下で; 型宣言<T>
はクラスレベルで既に宣言されているため、メソッドレベルでは必要ありません。
class MyClass<T> {
private T myMethod(T a){
return a;
}
}
ただし、クラスレベルの型パラメーターK、V、Z、Yは静的コンテキスト(ここでは静的メソッド)で使用できないため、以下は誤りです。
class Util <K, V, Z, Y>{
// Generic static method
public static boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
return p1.getKey().equals(p2.getKey()) &&
p1.getValue().equals(p2.getValue());
}
}
その他の有効なシナリオは
class MyClass<T> {
//Type declaration <T> already done at class level
private T myMethod(T a){
return a;
}
//<T> is overriding the T declared at Class level;
//So There is no ClassCastException though a is not the type of T declared at MyClass<T>.
private <T> T myMethod1(Object a){
return (T) a;
}
//Runtime ClassCastException will be thrown if a is not the type T (MyClass<T>).
private T myMethod1(Object a){
return (T) a;
}
// No ClassCastException
// MyClass<String> obj= new MyClass<String>();
// obj.myMethod2(Integer.valueOf("1"));
// Since type T is redefined at this method level.
private <T> T myMethod2(T a){
return a;
}
// No ClassCastException for the below
// MyClass<String> o= new MyClass<String>();
// o.myMethod3(Integer.valueOf("1").getClass())
// Since <T> is undefined within this method;
// And MyClass<T> don't have impact here
private <T> T myMethod3(Class a){
return (T) a;
}
// ClassCastException for o.myMethod3(Integer.valueOf("1").getClass())
// Should be o.myMethod3(String.valueOf("1").getClass())
private T myMethod3(Class a){
return (T) a;
}
// Class<T> a :: a is Class object of type T
//<T> is overriding of class level type declaration;
private <T> Class<T> myMethod4(Class<T> a){
return a;
}
}
そして最後に、Staticメソッドは常に明示的な<T>
宣言を必要とします。クラスレベルからは派生しませんClass<T>
。これは、クラスレベルTがインスタンスにバインドされているためです。
ジェネリクスの制限も読む
ワイルドカードとサブタイプ
ジェネリックメソッドの型引数