質問
ジェネリックスが導入されてから、Class がパラメータ化され、List.class が Class<List> を生成するようになりました。これは明らかです。
私が理解できないのは、それ自体がパラメータ化されたタイプのクラスのインスタンスを取得する方法です。クラス<リスト<文字列>>。このスニペットのように:
public class GenTest {
static <T> T instantiate(Class<T> clazz) throws Exception {
return clazz.newInstance();
}
public static void main(String[] args) throws Exception {
// Is there a way to avoid waring on the line below
// without using @SuppressWarnings("unchecked")?
// ArrayList.class is Class<ArrayList>, but I would like to
// pass in Class<ArrayList<String>>
ArrayList<String> l = GenTest.instantiate(ArrayList.class);
}
}
私はこの問題のバリエーションに頻繁に遭遇しますが、単に何かを見逃しているだけなのか、それとも本当に良い方法がないのか、まだわかりません。ご提案ありがとうございます。
解決
Class クラスは、型の実行時表現です。パラメーター化された型は実行時に型が消去されるため、Class のクラス オブジェクトは Class<List<Integer>> および Class<List<String>> のクラス オブジェクトと同じになります。
.class 表記を使用してインスタンスを作成できない理由は、これがクラス リテラルに使用される特別な構文であるためです。の Java言語仕様 特に、型がパラメーター化されている場合、この構文は禁止されています。そのため、List<String>.class は許可されません。
他のヒント
クラスは、クラス ローダーによってロードされたクラス (生の型) を表します。パラメータ化された型を表すには、java.lang.reflect.ParameterizedType を使用します。
あなたがやろうとしていることができるとは思えません。まず、インスタンス化メソッドはパラメータ化された型を扱っていることを知りません (java.util.Date.class を渡すことも簡単にできます)。第 2 に、消去があるため、実行時にパラメーター化された型で特に特殊なことを行うのは困難または不可能です。
別の方法で問題にアプローチする場合は、型推論など、他にも実行できる小さなトリックがあります。
public class GenTest
{
private static <E> List<E> createList()
{
return new ArrayList<E>();
}
public static void main(String[] args)
{
List<String> list = createList();
List<Integer> list2 = createList();
}
}
できることはインスタンス化することだけです List<String>
直接 そしてそれを呼び出します getClass()
:
instantiate(new List<String>() { ... }.getClass());
次のような複数の抽象メソッドを持つ型の場合 List
, 、これはかなり厄介です。しかし、残念なことに、サブクラスのコンストラクターを呼び出すと( new ArrayList<String>
) またはファクトリーメソッド (Collections.<String>emptyList()
)機能しません。