私は同様の質問を見てきましたが、あまり役に立ちませんでした。
たとえば、私はこの汎用クラスを持っています:
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クラスの形式が変更されました
唯一の方法は、クラスをインスタンス変数に保存し、コンストラクターの引数として要求することです。
public class ContainerTest<T>
{
private Class<T> tClass;
public ContainerTest(Class<T> tClass) {
this.tCLass = tClass;
}
public void doSomething()
{
//access tClass here
}
}
リフレクションの方法に興味があるなら、この素晴らしい記事で部分的な解決策を見つけました: 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());
}
}
クラス内から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.
}
}
いいえ。 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);
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;
このように定義できる場合
public class ContainerTest<T>
{
public void doSomething(T clazz)
{
}
}
それは可能です
そこに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で説明されています。
クライアントは空の匿名サブクラスを作成します。これにより、匿名クラスの型階層に型パラメーターが埋め込まれるため、消去しても実行時に再構成できます。