ジェネリックと彼らが舞台裏で実際に何をしているのかについてのよい議論があります。この質問Vector<int[]>
なので、は整数配列のベクトルであり、HashTable<String, Person>
はキーが文字列で値が s であるテーブルであることは誰もが知っていますPerson
。しかし、 の使い方がわかりませんClass<>
。
Java クラスClass
もテンプレート名を取ることになっています (少なくとも Eclipse の黄色い下線でそう言われています)。 そこに何を入れればよいのかわかりません。 オブジェクトの全体的なポイントは、Class
リフレクションなどのために、オブジェクトに関する情報が完全にない場合です。 なぜオブジェクトがClass
保持するクラスを指定しなければならないのですか? 明らかにわかりません。そうでなければ、オブジェクトは使用せずClass
、特定のクラスを使用します。
ベストアンサー1
私たちが知っているのは、「任意のクラスのすべてのインスタンスは、そのタイプのクラスの同じ 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はCarNameString
の型として使用できます
または、TはmodelNumberInteger
の型として使用できます。
または、T は有効な車インスタンスObject
の型として使用できます。
上記は、実行時に異なる方法で使用できる単純な POJO です。
コレクション (例) List、Set、Hashmap は、T の宣言に従ってさまざまなオブジェクトで機能する最適な例ですが、T を String として宣言すると、
StringHashMap<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;
}
}
そして最後に、静的メソッドは常に明示的な<T>
宣言を必要とします。クラス レベルから派生しませんClass<T>
。これは、クラス レベル T がインスタンスにバインドされているためです。
こちらもお読みくださいジェネリック医薬品の制限