実行時にクラスのジェネリック型を取得する


508

どうすればこれを達成できますか?

public class GenericClass<T>
{
    public Type getMyType()
    {
        //How do I return the type of T?
    }
}

これまでに試みたすべてのことはObject、使用される特定の型ではなく、常に型を返します。


3
@SamuelVidalこれは.NETではなく、Javaです。
フロンティア

回答:


317

他の人が述べたように、それは特定の状況での反射を介してのみ可能です。

タイプが本当に必要な場合、これは通常の(タイプセーフな)回避策パターンです。

public class GenericClass<T> {

     private final Class<T> type;

     public GenericClass(Class<T> type) {
          this.type = type;
     }

     public Class<T> getMyType() {
         return this.type;
     }
}

58
私はこの答えが好きですが、インスタンス化するのは少し面倒です:GenericClass <AnotherClass> g = new GenericClass <AnotherClass>(AnotherClass.class);
Eliseo Ocampos 2013

1
dao / factory / managerのアプローチを使用すると、さらに詳細になります。Foo foo1 = GetDao<Foo>(Foo.class).get(Foo.class, 1)
djmj 14年

2
それは本当ですが、コンテナ/リフレクションによってインスタンス化されるステートレスリモートBeanのようなすべてのケースで機能するわけではありません。
djmj 2014

6
私の以前のコメントのフォローアップと同じように-リフレクションで遊んで多くの苦痛の後、私はこの答えを使用することになりました。
トマーシュ・ザト-モニカ

18
汎用の静的ファクトリメソッドを提供することで、余分な参照を回避できます。次のようなものpublic static <T> GenericClass<T> of(Class<T> type) {...}を呼び出しますGenericClass<String> var = GenericClass.of(String.class)。少しいい。
Joeri Hendrickx 2016

263

私はこのようなものを見ました

private Class<T> persistentClass;

public Constructor() {
    this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
                            .getGenericSuperclass()).getActualTypeArguments()[0];
 }

休止状態GenericDataAccessObjects


84
この手法は、型パラメーターが直接のスーパークラスで定義されている場合に機能しますが、型パラメーターが型階層の他の場所で定義されている場合は失敗します。より複雑なケースを処理するには、TypeToolsなどを使用できます。ドキュメントには、より洗練されたGeneric DAOの例が含まれています。
ジョナサン

25
これは、CLASSが一般的な宣言を持つものを実装または拡張するときに使用される実際の型パラメーターのみを返します。INSTANCEがインスタンス化されるときに使用される実際の型パラメーターを返しません。言い換えれば、それはCANでいることを伝えclass A implements Comparable<String>、実際の型パラメータがあるStringが、それはことはできませんでいることを伝えSet<String> a = new TreeSet<String>()、実際の型パラメータがありますString。実際、タイプパラメータ情報は、他の回答で説明されているように、コンパイル後に「消去」されます。
Siu Ching Pong -Asuka Kenji-

32
私はjava.lang.Class cannot be cast to java.lang.reflect.ParameterizedTypeこの答えを得ようとしています。
回復モニカ-トマーシュZato

4
このアプローチはClass-Mate、ジャクソンの人々からも利用できます。私はここに要点を書きましたgist.github.com/yunspace/930d4d40a787a1f6a7d1
yunspace

5
@TomášZato上記のコードを呼び出すだけで、同じ例外が返されました。少し遅いのはわかっていますが、とにかく、私の場合、(Class<T>) ((ParameterizedType)getClass().getSuperclass().getGenericSuperclass()).getActualTypeArguments()実際の型引数を取得するために呼び出す必要がありました。
AndrewMcCoist 2017

99

ジェネリックは実行時に具体化されません。これは、情報が実行時に存在しないことを意味します。

下位互換性を維持しながらJavaにジェネリックスを追加することは、見習いでした(これに関する独創的な論文を見ることができます: 未来を過去に向けて安全にする:ジェネリックをJavaプログラミング言語に追加する)。

このテーマに関する豊富な文献があり、現在の状態に不満抱いている人もいれば、実際にはルアーであり、本当の必要性はないと言う人もいます。あなたは両方のリンクを読むことができます、私はそれらが非常に興味深いと思いました。


179
もちろん、私たちが不満を持っている、.NETは、はるかに優れた汎用的な処理機構がある
Pacerier

6
@Pacerier:しかし、具体化されたジェネリックだけでは、Javaを.NETのレベルに引き上げることはできません。ジェネリック領域で.NETが優れている理由として、値型とそれらに特化したコードが少なくとも同等に重要です。
Joachim Sauer

@JoachimSauer、はい値型。私はいつもそれらをJavaで望んでいた。ところで、特殊なコードとはどういう意味ですか?
パセリエ2012

3
@ spaaarky21いいえ、ジェネリック型パラメーターはコンパイル時に削除されます(いわゆる「消去」、グーグルできます)。FrVaBeの答えのトリックは、スーパークラスの型パラメーターが静的に知られている場合にのみ機能します(Johnathnによる最初のコメントを参照)
ewernli 14

1
Javaの型消去は歴史的な設計上の欠陥です。それを回避するために、それを実装するために書かれたよりも多くのコードが書かれました。
Abhijit Sarkar 2018年

68

グアバを使用してください。

import com.google.common.reflect.TypeToken;
import java.lang.reflect.Type;

public abstract class GenericClass<T> {
  private final TypeToken<T> typeToken = new TypeToken<T>(getClass()) { };
  private final Type type = typeToken.getType(); // or getRawType() to return Class<? super T>

  public Type getType() {
    return type;
  }

  public static void main(String[] args) {
    GenericClass<String> example = new GenericClass<String>() { };
    System.out.println(example.getType()); // => class java.lang.String
  }
}

しばらく前に、抽象クラスやサブクラスを含む本格的な例をいくつかここに投稿しました

注:これはあなたがインスタンス化する必要があり、サブクラスGenericClassそれは正しくタイプパラメータをバインドすることができるようにします。それ以外の場合は、型をとして返しますT


3
空の匿名サブクラスを作成していることに注意してください(最後の2つの中括弧を参照)。これはリフレクションを使用して、Javaのランタイム型の消去と戦います。詳細については、こちらをご覧ください:code.google.com/p/guava-libraries/wiki/ReflectionExplained
Cody A. Ray

3
@ CodyA.Rayあなたのコードはjava.lang.IllegalArgumentException: class com.google.common.reflect.TypeToken isn't parameterized。そこで、行new TypeToken(getClass()) { }をに変更しましたnew TypeToken<T>(getClass()) { }。現在、コードは問題なく実行されていますが、Typeはまだ「T」です。これを参照してください:gist.github.com/m-manu/9cda9d8f9d53bead2035
Manu Manjunath

3
@Dominikコピーして貼り付けて自分でテストできる更新された例をご覧ください。また、サブクラスをインスタンス化する必要があることを示す注記を追加しました(図のように)。一般的なエチケットのアドバイスとして、「希望的思考」のポスターを非難する前に、リンクされた記事と関連するjavadocを読んでください。同様の製品コードを複数回使用しました。私がデモンストレーションしているGuavaヘルパーは、この正確なユースケースを対象としており、javadocはこの質問に対してほぼ正確な答えを示しています。docs.guava-libraries.googlecode.com/git/javadoc/com/google/...
コーディA.レイ

1
この答えはJava8でうまく機能します。私はさまざまなタイプを出力するためのインターフェースとファクトリークラスを持っているので、ユーザーがタイプを簡単に判別できるようにしたかったのです。私のインターフェースにデフォルトのメソッドを追加しました: default Type getParameterType() { final TypeToken<T> typeToken = new TypeToken<T>(getClass()) {}; final Type type = typeToken.getType(); return type; }
Richard Sand

2
@ CodyA.Rayこれはのサブクラスでのみ機能するため、誤った使用法がコンパイルされないようにGenericClass、そのクラスを作成する必要abstractがあります。
マーティン

37

できますよ。

下位互換性のため、Javaは実行時にこの情報を使用しません。しかし、情報は実際にはメタデータとして存在し、リフレクションを介してアクセスできます(ただし、タイプチェックにはまだ使用されません)。

公式APIから:

http://download.oracle.com/javase/6/docs/api/java/lang/reflect/ParameterizedType.html#getActualTypeArguments%28%29

ただし、シナリオでは、リフレクションは使用しません。私は個人的にはフレームワークのコードにそれを使用する傾向があります。あなたの場合、コンストラクターのパラメーターとして型を追加するだけです。


10
getActualTypeArgumentsは、直接のクラスの型引数のみを返します。Tを階層のどこにでもパラメーター化できる複雑な型の階層がある場合、それが何であるかを理解するために少し作業を行う必要があります。これは、多かれ少なかれTypeToolsが行うことです。
ジョナサン

36

Javaジェネリックはほとんどがコンパイル時です。これは、型情報が実行時に失われることを意味します。

class GenericCls<T>
{
    T t;
}

のようなものにコンパイルされます

class GenericCls
{
   Object o;
}

実行時に型情報を取得するには、それをctorの引数として追加する必要があります。

class GenericCls<T>
{
     private Class<T> type;
     public GenericCls(Class<T> cls)
     {
        type= cls;
     }
     Class<T> getType(){return type;}
}

例:

GenericCls<?> instance = new GenericCls<String>(String.class);
assert instance.getType() == String.class;

9
private final Class<T> type;
naXa

どのように私はそれから配列型を作成することができますType t = //String[]
パヴェルCioch

@PawelCioch java.lang.reflect.Array.newInstance(elementtype、length); これが役に立てば幸いです(javadocはdocs.oracle.com/javase/8/docs/api/java/lang/reflect/…にあります
josefx '22

@PawelCiochは、作成された配列から型を取得するための.getClass()をミスしました。配列クラスを取得する直接的な方法はないようです。ほとんどのJavaコレクションは、代わりにObject []を使用します。
josefx 2015

23
public abstract class AbstractDao<T>
{
    private final Class<T> persistentClass;

    public AbstractDao()
    {
        this.persistentClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
                .getActualTypeArguments()[0];
    }
}

3
この回答は、質問されたときに機能するソリューションであるため、賛成しています。ただし、私のように複数のGenericクラスを持つクラス階層を上に移動したい場合は、これは機能しません。実際のクラスの代わりにjava.lang.objectを取得するからです。
KMC、

3
このソリューションは、ジェネリック型を保持するクラスがABSTRACTである場合にのみ機能することに注意してください
BabaNew

Java 11で抽象クラスを使用できませんでした
JRA_TLL '26

@JRA_TLLあなたは明らかに何か間違ったことをしました。私はJava 12でそれを使用しただけで、魅力のように動作します。
グーギー

ビュー階層を上に移動する場合は、genericSuperclassをClass <*>にキャストして、genericSuperclassを取得できます。できればループで。
fupduck

21

私はフォローアプローチを使用しました:

public class A<T> {

    protected Class<T> clazz;

    public A() {
        this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    public Class<T> getClazz() {
        return clazz;
    }
}

public class B extends A<C> {
   /* ... */
    public void anything() {
       // here I may use getClazz();
    }
}

9
このサンプルコードで「スレッド "main"の例外java.lang.ClassCastException:java.lang.Classをjava.lang.reflect.ParameterizedTypeにキャストできません」を取得しました
yuyang

16

私はあなたができるとは思いません、Javaはコンパイル時に型消去を使用するので、コードは、ジェネリック以前に作成されたアプリケーションやライブラリと互換性があります。

Oracle Docsから:

タイプ消去

ジェネリックはJava言語に導入され、コンパイル時により厳密な型チェックを提供し、ジェネリックプログラミングをサポートします。ジェネリックを実装するために、Javaコンパイラーは型消去を以下に適用します。

ジェネリック型のすべての型パラメーターをその境界または型パラメーターが無制限の場合はObjectで置き換えます。したがって、生成されたバイトコードには、通常のクラス、インターフェース、およびメソッドのみが含まれます。型の安全性を維持する必要がある場合は、型キャストを挿入します。拡張ジェネリック型のポリモーフィズムを保持するためのブリッジメソッドを生成します。型の消去により、パラメーター化された型の新しいクラスが作成されなくなります。その結果、ジェネリックスは実行時のオーバーヘッドを発生させません。

http://docs.oracle.com/javase/tutorial/java/generics/erasure.html


うん、それは不可能です。Javaが機能するには、具体化されたジェネリックが必要です。
Henning

15

Ian Robertsonがこの記事で説明した手法うまくます。

短くて汚い例:

 public abstract class AbstractDAO<T extends EntityInterface, U extends QueryCriteria, V>
 {
    /**
     * Method returns class implementing EntityInterface which was used in class
     * extending AbstractDAO
     *
     * @return Class<T extends EntityInterface>
     */
    public Class<T> returnedClass()
    {
        return (Class<T>) getTypeArguments(AbstractDAO.class, getClass()).get(0);
    }

    /**
     * Get the underlying class for a type, or null if the type is a variable
     * type.
     *
     * @param type the type
     * @return the underlying class
     */
    public static Class<?> getClass(Type type)
    {
        if (type instanceof Class) {
            return (Class) type;
        } else if (type instanceof ParameterizedType) {
            return getClass(((ParameterizedType) type).getRawType());
        } else if (type instanceof GenericArrayType) {
            Type componentType = ((GenericArrayType) type).getGenericComponentType();
            Class<?> componentClass = getClass(componentType);
            if (componentClass != null) {
                return Array.newInstance(componentClass, 0).getClass();
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * Get the actual type arguments a child class has used to extend a generic
     * base class.
     *
     * @param baseClass the base class
     * @param childClass the child class
     * @return a list of the raw classes for the actual type arguments.
     */
    public static <T> List<Class<?>> getTypeArguments(
            Class<T> baseClass, Class<? extends T> childClass)
    {
        Map<Type, Type> resolvedTypes = new HashMap<Type, Type>();
        Type type = childClass;
        // start walking up the inheritance hierarchy until we hit baseClass
        while (!getClass(type).equals(baseClass)) {
            if (type instanceof Class) {
                // there is no useful information for us in raw types, so just keep going.
                type = ((Class) type).getGenericSuperclass();
            } else {
                ParameterizedType parameterizedType = (ParameterizedType) type;
                Class<?> rawType = (Class) parameterizedType.getRawType();

                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
                for (int i = 0; i < actualTypeArguments.length; i++) {
                    resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
                }

                if (!rawType.equals(baseClass)) {
                    type = rawType.getGenericSuperclass();
                }
            }
        }

        // finally, for each actual type argument provided to baseClass, determine (if possible)
        // the raw class for that type argument.
        Type[] actualTypeArguments;
        if (type instanceof Class) {
            actualTypeArguments = ((Class) type).getTypeParameters();
        } else {
            actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
        }
        List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>();
        // resolve types by chasing down type variables.
        for (Type baseType : actualTypeArguments) {
            while (resolvedTypes.containsKey(baseType)) {
                baseType = resolvedTypes.get(baseType);
            }
            typeArgumentsAsClasses.add(getClass(baseType));
        }
        return typeArgumentsAsClasses;
    }
  }

3
このコードのどの特定の行が実際に読み取られ、実行時の型パラメーターですか?
Ivan Matavulj

ここに?Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
Ondrej Bozek 2016

9

別のエレガントな解決策があると思います。

あなたがしたいことは、(安全に)ジェネリック型パラメーターの型をコンセレートクラスからスーパークラスに「渡す」ことです。

クラスタイプをクラスの「メタデータ」と考えることを許可すると、実行時にメタデータをエンコードするためのJavaメソッドが提案されます。

まず、これらの行に沿ってカスタムアノテーションを定義します。

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EntityAnnotation {
    Class entityClass();
}

次に、アノテーションをサブクラスに追加する必要があります。

@EntityAnnotation(entityClass =  PassedGenericType.class)
public class Subclass<PassedGenericType> {...}

次に、このコードを使用して、基本クラスのクラス型を取得できます。

import org.springframework.core.annotation.AnnotationUtils;
.
.
.

private Class getGenericParameterType() {
    final Class aClass = this.getClass();
    EntityAnnotation ne = 
         AnnotationUtils.findAnnotation(aClass, EntityAnnotation.class);

    return ne.entityClass();
}

このアプローチのいくつかの制限は次のとおりです。

  1. ジェネリック型(PassedGenericType)は、DRY以外のではなく2つの場所で。
  2. これは、具象サブクラスを変更できる場合にのみ可能です。

はい、それは非DRYですが、上記で提案された拡張アプローチよりもきれいです。私はそれが好き。ありがとう
agodinhost

8

これは私の解決策です:

import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

public class GenericClass<T extends String> {

  public static void main(String[] args) {
     for (TypeVariable typeParam : GenericClass.class.getTypeParameters()) {
      System.out.println(typeParam.getName());
      for (Type bound : typeParam.getBounds()) {
         System.out.println(bound);
      }
    }
  }
}

10
これはこの質問に対する答えではありません。
Adam Arold、2013

1
私のコードは質問の正確な解決策ではありません。これは、クラスのジェネリック型パラメーターを返しますが、Tの実際の型は返しません。しかし、それは、質問に困惑して私の解決策を探している他の人にとって役立つかもしれません。
Matthias M

1
getClass()。getGenericSuperclass()でも同じ効果が得られます。
Gorky

5

これが実際の解決策です!!!

@SuppressWarnings("unchecked")
    private Class<T> getGenericTypeClass() {
        try {
            String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
            Class<?> clazz = Class.forName(className);
            return (Class<T>) clazz;
        } catch (Exception e) {
            throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
        }
    } 

注: スーパークラス
1 としてのみ使用できます。型付きクラス(Child extends Generic<Integer>
または

2. で拡張する必要があります。匿名実装(new Generic<Integer>() {};) として作成する必要があります。


4

できません。T型のメンバー変数をクラスに追加すると(初期化する必要すらありません)、それを使用して型を回復できます。


2
おっと、そう。コンストラクタから初期化する必要があります。
andrewmu 2010

4

ここに私が1回か2回使用しなければならなかった1つの方法があります:

public abstract class GenericClass<T>{
    public abstract Class<T> getMyType();
}

に加えて

public class SpecificClass extends GenericClass<String>{

    @Override
    public Class<String> getMyType(){
        return String.class;
    }
}

4
これは技術的には機能しますが、一般的なケースを解決するものではありません。それが、元のポスターの目的です。
ggb667 2013年

本来のように、これは投票に値するわけではありません-元のポスターは明確ではありませんでした。この回答申し出デザインパターンない仕事をし、実装が容易であるが、一般的なクラスが抽象的にするために適して提供します。
VirtualMichael 2015

4

このタクシーの簡単な解決策の1つは次のようになります

public class GenericDemo<T>{
    private T type;

    GenericDemo(T t)
    {
        this.type = t;
    }

    public String getType()
    {
        return this.type.getClass().getName();
    }

    public static void main(String[] args)
    {
        GenericDemo<Integer> obj = new  GenericDemo<Integer>(5);
        System.out.println("Type: "+ obj.getType());
    }
}

3

ここでいくつかの回答を完了するには、再帰を利用して、階層の高さに関係なく、MyGenericClassのParametrizedTypeを取得する必要がありました。

private Class<T> getGenericTypeClass() {
        return (Class<T>) (getParametrizedType(getClass())).getActualTypeArguments()[0];
}

private static ParameterizedType getParametrizedType(Class clazz){
    if(clazz.getSuperclass().equals(MyGenericClass.class)){ // check that we are at the top of the hierarchy
        return (ParameterizedType) clazz.getGenericSuperclass();
    } else {
        return getParametrizedType(clazz.getSuperclass());
    }
}

1

ここに私のトリックがあります:

public class Main {

    public static void main(String[] args) throws Exception {

        System.out.println(Main.<String> getClazz());

    }

    static <T> Class getClazz(T... param) {

        return param.getClass().getComponentType();
    }

}

1
注:型変数の場合、これは機能しませんT。場合にT型変数であり、可変引数は、消去のアレイを作成しますT。たとえば、http : //ideone.com/DIPNwdを参照してください。
Radiodef 2015

1
これは「オブジェクト」を返します
yahya

あなたは🤔他のいくつかの質問に答えるためにしようとしているかもしれ
カーン

1

ジェネリック型を使用して変数を格納する場合に備えて、次のようにgetClassTypeメソッドを追加すると、この問題を簡単に解決できます。

public class Constant<T> {
  private T value;

  @SuppressWarnings("unchecked")
  public Class<T> getClassType () {
    return ((Class<T>) value.getClass());
  }
}

次のように、提供されたクラスオブジェクトを使用して、それが特定のクラスのインスタンスであるかどうかを確認します。

Constant<?> constant = ...;
if (constant.getClassType().equals(Integer.class)) {
    Constant<Integer> integerConstant = (Constant<Integer>)constant;
    Integer value = integerConstant.getValue();
    // ...
}

2
残念ながら、これには問題があります。まず、場合は何valueですかnull?第二に、もしvalueのサブクラスがあるとしTたら?Constant<Number> c = new Constant<Number>(new Integer(0)); Class<Number> n = c.getClassType();復帰Integer.classすべきときに復帰しNumber.classます。戻る方が正しいでしょうClass<? extends T>Integer.class ですが、ではあり Class<? extends Number>ませんClass<Number>
Radiodef 2015

1

これが私の解決策です

public class GenericClass<T>
{
    private Class<T> realType;

    public GenericClass() {
        findTypeArguments(getClass());
    }

    private void findTypeArguments(Type t) {
        if (t instanceof ParameterizedType) {
            Type[] typeArgs = ((ParameterizedType) t).getActualTypeArguments();
            realType = (Class<T>) typeArgs[0];
        } else {
            Class c = (Class) t;
            findTypeArguments(c.getGenericSuperclass());
        }
    }

    public Type getMyType()
    {
        // How do I return the type of T? (your question)
        return realType;
    }
}

クラス階層のレベルがいくつあっても、このソリューションは引き続き機能します。次に例を示します。

public class FirstLevelChild<T> extends GenericClass<T> {

}

public class SecondLevelChild extends FirstLevelChild<String> {

}

この場合、getMyType()= java.lang.String


これはTのタイプを返しません。コードがTypeをClass <T>に
変換

これが私が作ったオンラインサンプルです。[コンパイルして実行]をクリックすると、結果を取得できます。 tutorialspoint.com/...
林ゆうチェン

私のために働く-WildFly Weld CDIが別の方法を破ったとき。
アンドレ

私が得たException in thread "main" java.lang.NullPointerException at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.<init>(Main.java:43) at Main.main(Main.java:61)
陽陽

0
public static final Class<?> getGenericArgument(final Class<?> clazz)
{
    return (Class<?>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
}

0

これが私の解決策です。例はそれを説明するべきです。唯一の要件は、サブクラスがオブジェクトではなくジェネリック型を設定する必要があることです。

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.Map;

public class TypeUtils {

    /*** EXAMPLES ***/

    public static class Class1<A, B, C> {

        public A someA;
        public B someB;
        public C someC;

        public Class<?> getAType() {
            return getTypeParameterType(this.getClass(), Class1.class, 0);
        }

        public Class<?> getCType() {
            return getTypeParameterType(this.getClass(), Class1.class, 2);
        }
    }

    public static class Class2<D, A, B, E, C> extends Class1<A, B, C> {

        public B someB;
        public D someD;
        public E someE;
    }

    public static class Class3<E, C> extends Class2<String, Integer, Double, E, C> {

        public E someE;
    }

    public static class Class4 extends Class3<Boolean, Long> {

    }

    public static void test() throws NoSuchFieldException {

        Class4 class4 = new Class4();
        Class<?> typeA = class4.getAType(); // typeA = Integer
        Class<?> typeC = class4.getCType(); // typeC = Long

        Field fieldSomeA = class4.getClass().getField("someA");
        Class<?> typeSomeA = TypeUtils.getFieldType(class4.getClass(), fieldSomeA); // typeSomeA = Integer

        Field fieldSomeE = class4.getClass().getField("someE");
        Class<?> typeSomeE = TypeUtils.getFieldType(class4.getClass(), fieldSomeE); // typeSomeE = Boolean


    }

    /*** UTILS ***/

    public static Class<?> getTypeVariableType(Class<?> subClass, TypeVariable<?> typeVariable) {
        Map<TypeVariable<?>, Type> subMap = new HashMap<>();
        Class<?> superClass;
        while ((superClass = subClass.getSuperclass()) != null) {

            Map<TypeVariable<?>, Type> superMap = new HashMap<>();
            Type superGeneric = subClass.getGenericSuperclass();
            if (superGeneric instanceof ParameterizedType) {

                TypeVariable<?>[] typeParams = superClass.getTypeParameters();
                Type[] actualTypeArgs = ((ParameterizedType) superGeneric).getActualTypeArguments();

                for (int i = 0; i < typeParams.length; i++) {
                    Type actualType = actualTypeArgs[i];
                    if (actualType instanceof TypeVariable) {
                        actualType = subMap.get(actualType);
                    }
                    if (typeVariable == typeParams[i]) return (Class<?>) actualType;
                    superMap.put(typeParams[i], actualType);
                }
            }
            subClass = superClass;
            subMap = superMap;
        }
        return null;
    }

    public static Class<?> getTypeParameterType(Class<?> subClass, Class<?> superClass, int typeParameterIndex) {
        return TypeUtils.getTypeVariableType(subClass, superClass.getTypeParameters()[typeParameterIndex]);
    }

    public static Class<?> getFieldType(Class<?> clazz, AccessibleObject element) {
        Class<?> type = null;
        Type genericType = null;

        if (element instanceof Field) {
            type = ((Field) element).getType();
            genericType = ((Field) element).getGenericType();
        } else if (element instanceof Method) {
            type = ((Method) element).getReturnType();
            genericType = ((Method) element).getGenericReturnType();
        }

        if (genericType instanceof TypeVariable) {
            Class<?> typeVariableType = TypeUtils.getTypeVariableType(clazz, (TypeVariable) genericType);
            if (typeVariableType != null) {
                type = typeVariableType;
            }
        }

        return type;
    }

}

-1

私は上記の@Moesioと同じことをしましたが、Kotlinでは次のようにして行うことができます。

class A<T : SomeClass>() {

    var someClassType : T

    init(){
    this.someClassType = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<T>
    }

}

-4

誰かに役立つかもしれません。java.lang.ref.WeakReferenceを使用できます。こちらです:

class SomeClass<N>{
  WeakReference<N> variableToGetTypeFrom;

  N getType(){
    return variableToGetTypeFrom.get();
  }
}

このクラスはどのように使用されることになっていますか?なんでWeakReference?コードだけでなく、回答についても説明してください。
Abhijit Sarkar

したがって、aがあるSomeClass<MyClass> 場合、インスタンス化SomeClassgetTypeてそのインスタンスを呼び出し、ランタイムをにすることができますMyClass
TheLetch

もちろんですが、なぜWeakReferenceですか?あなたが言ったことは、他のほとんどの答えと変わりません。
Abhijit Sarkar 2018年

最初に私のアプローチは短く(コードが少ない)、次に弱い参照は参照がファイナライズ可能になることを妨げず、私が知る限り、リフレクションを使用しないため高速です
TheLetch

これはこれは、FYI、ラッパーの文字通りあらゆる種類で行うことができ、そのタイプのオブジェクトを返し、何の種類を取得していません(AtomicReferenceListSet)。
Frontear

-5

私はこれが簡単に理解でき、簡単に説明できる解決策であることがわかりました

public class GenericClass<T> {

    private Class classForT(T...t) {
        return t.getClass().getComponentType();
    }

    public static void main(String[] args) {
        GenericClass<String> g = new GenericClass<String>();

        System.out.println(g.classForT());
        System.out.println(String.class);
    }
}

説明してください(T...t)。(そのため、このコードは機能しません。)
クリストファーシュナイダー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.