web-dev-qa-db-ja.com

List <T>からClass <T>を取得する方法

これを尋ねなければならないのはまったくばかげていますが、なぜ次のJavaコードがコンパイルされないのか理解できませんでした:

void <T> doSomething(List<T> items) {
    Class<? extends T> clazz = items.get(0).getClass();
    ...
}

Java docから:

実際の結果タイプはClass <? | X |>を拡張します| X | getClassが呼び出される式の静的タイプの消去です。たとえば、次のコードではキャストは必要ありません。

数値n = 0;クラス<? Number> c = n.getClass();を拡張します。

編集:

  1. 見つかりました この素敵な説明 静的型の消去消去の意味。

  2. スーパータイプトークン と呼ばれる、サブクラスを使用してジェネリック型情報を保持する方法があります。現在削除された回答は、Guavaライブラリにこれを悪用するための 便利なユーティリティ があることを指摘しました。

  3. 以下は、ジェネリック型をリフレクティブに抽出する際の 素晴らしい記事 といいます GenTyRef と呼ばれる素敵なライブラリです。

  4. GenTyRefをフォークして、AnnotatedTypesの操作のサポートを追加しました(Java 8で導入)。これは GenAnTyRef と呼ばれます(Maven Centralにあります)。

18
kaqqao

items.get(0)の静的タイプの消去はObjectです(Tはコンパイル中に消去されるため)。

したがって、items.get(0).getClass()Class<? extends Object>ではなくClass<? extends T>を返します。これは、試行した割り当てが失敗した理由を説明しています。

これはコンパイルを渡します:

Class<? extends Object> clazz = items.get(0).getClass();

ジェネリックパラメーターのClassをそのメソッドが認識できるようにする場合は、追加の引数として渡すことができます。

void doSomething(List<T> items, Class<T> clazz) {

}
25
Eran

まず、メソッドの型パラメーターとしてTを定義する必要があります:<T> void doSomething。次に、Class<? extends T>へのキャストが必要です。だからこれはあなたが一緒にする方法です:

<T> void doSomething(List<T> items) {
    Class<? extends T> clazz = (Class<? extends T>) items.get(0).getClass();
    ...
}
1
Tamas Rev