web-dev-qa-db-ja.com

Java Genericsで型変数のクラスを取得する方法

私は同様の質問を見てきましたが、あまり役に立ちませんでした。

たとえば、私はこの汎用クラスを持っています:

public class ContainerTest<T>
{

    public void doSomething()
    {
        //I want here to determinate the Class of the type argument (In this case String)
    }
}

このコンテナクラスを使用する別のクラス

public class TestCase
{

    private ContainerTest<String> containerTest;

    public void someMethod()
    {
        containerTest.doSomething();
    }
}

メソッドdoSomething()で型引数のクラスを決定することは可能ですか?without明示的な型を持つvariable/fieldまたはContainerTestのconstructorクラス?

更新:ContainerTestクラスの形式が変更されました

20
ZeDonDino

唯一の方法は、クラスをインスタンス変数に保存し、コンストラクターの引数として要求することです。

public class ContainerTest<T>
{
    private Class<T> tClass;
    public ContainerTest(Class<T> tClass) {
        this.tCLass = tClass;
    }

    public void doSomething()
    {
        //access tClass here
    }
}
13
Didier L

リフレクションの方法に興味があるなら、この素晴らしい記事で部分的な解決策を見つけました: http://www.artima.com /weblogs/viewpost.jsp?thread=20886

つまり、Java.lang.Class.getGenericSuperclass()メソッドとJava.lang.reflect.ParameterizedType.getActualTypeArguments()メソッドを使用できますが、親スーパークラスをサブクラス化する必要があります。

次のスニペットは、スーパークラスAbstractUserTypeを直接拡張するクラスに対して機能します。より一般的なソリューションについては、参照記事を参照してください。

import Java.lang.reflect.ParameterizedType;


public class AbstractUserType<T> {

    public Class<T> returnedClass() {
        ParameterizedType parameterizedType = (ParameterizedType) getClass()
                .getGenericSuperclass();

        @SuppressWarnings("unchecked")
        Class<T> ret = (Class<T>) parameterizedType.getActualTypeArguments()[0];

        return ret;
    }

    public static void main(String[] args) {
        AbstractUserType<String> myVar = new AbstractUserType<String>() {};

        System.err.println(myVar.returnedClass());
    }

}
10
dedek

クラス内からGeneric Type引数を取得する「クリーンな」方法はありません。代わりに、一般的なパターンは、ジェネリック型のクラスをコンストラクターに渡し、Java.util.EnumMap実装で行われるのと同じように内部プロパティとして保持することです。

http://docs.Oracle.com/javase/1.5.0/docs/api/Java/util/EnumMap.htmlhttp://grepcode.com/file/repository。 grepcode.com/Java/root/jdk/openjdk/6-b14/Java/util/EnumMap.Java

public class ContainerTest<T> {

    Class<T> type;
    T t;

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

    public void setT(T t) {
        this.t = t;
    }

    public T getT() {
        return t;
    }

    public void doSomething() {
        //There you can use "type" property.
    }
}
5
Renaud

いいえ。 type erasure (typeパラメーターはObject + type castとしてコンパイルされている)のため不可能です。 実際に実行時に型を知る/強制する必要がある場合、Classオブジェクトへの参照を保存できます。

public class ContainerTest<T> {
   private final Class<T> klass;
   private final List<T> list = new ArrayList<T>();

   ContainerTest(Class<T> klass) {
     this.klass = klass;
   }

   Class<T> getElementClass() {
     return klass;
   }

   void add(T t) {
      //klass.cast forces a runtime cast operation
      list.add(klass.cast(t));
   }
}

使用する:

ContainerTest<String> c = new ContainerTest<>(String.class);
2
Javier

Tの値を学習するには、ContainerTestをサブクラス化することにより、型定義でそれをキャプチャする必要があります。

class MyStringClass extends ContainerTest<String> {}

必要に応じて、匿名クラスでこれを行うこともできます。

ContainerTest<String> myStringClass = new ContainerTest<String>{}();

Tの値を解決するには、 TypeTools を使用できます。

Class<?> stringType = TypeResolver.resolveRawArgument(ContainerTest.class, myStringClass.getClass());
assert stringType == String.class;
1
Jonathan

このように定義できる場合

public class ContainerTest<T>
{

    public void doSomething(T clazz)
    {

    }
}

それは可能です

0
Arsen Alexanyan

そこにis GuavaのTypeTokenを使用してそれをキャプチャすることにより、タイプパラメータのランタイムタイプを取得する方法があります。ソリューションの欠点は、Containerのインスタンスが必要になるたびに匿名サブクラスを作成する必要があることです。

class Container<T> {

    TypeToken<T> tokenOfContainedType = new TypeToken<T>(getClass()) {};

    public Type getContainedType() {
        return tokenOfContainedType.getType();
    }
}

class TestCase {

    // note that containerTest is not a simple instance of Container,
    // an anonymous subclass is created
    private Container<String> containerTest = new Container<String>() {};

    @Test
    public void test() {
        Assert.assertEquals(String.class, containerTest.getContainedType());
    }
}

このソリューションのキーは、上記のコードで使用されているTypeTokenのコンストラクターのJavaDocで説明されています。

クライアントは空の匿名サブクラスを作成します。これにより、匿名クラスの型階層に型パラメーターが埋め込まれるため、消去しても実行時に再構成できます。

0
zagyi