我具有以下类结构:
class A<T> {
B<T> b;
}
class B<T> {
T t;
}
class StringConsumer {
A<String> a;
}
class LongConsumer {
A<Long> a;
}
鉴于我有一个消费者类之一的实例,是否可以获取consumer.a.b
的类型参数?我发现,如果将a
声明为StringA a;
,其中class StringA extends A<String>
使用TypeTools
答案 0 :(得分:1)
由于您的使用者类声明了没有任何类型变量的字段a
,因此您所需的所有键入信息都将在运行时出现。
虽然可以直接使用反射来实现您所要的内容,但是它很快就会变得疯狂,因此我强烈建议您使用GenTyRef或GeAnTyRef(我维护的增强型分叉)。 / p>
StringConsumer consumer = new StringConsumer(); //Or LongConsumer
Field a = consumer.getClass().getDeclaredField("a");
//typeOfA represents A<String, String>
ParameterizedType typeOfA = (ParameterizedType) GenericTypeReflector.getExactFieldType(a, consumer.getClass());
Type[] args = typeOfA.getActualTypeArguments();
System.out.println(args[0]); //String
System.out.println(args[1]); //String
Field b = A.class.getDeclaredField("b");
//or if you need it dynamic ((Class)typeOfA.getRawType()).getDeclaredField("b")
//or GenericTypeReflector.erase(typeOfA).getDeclaredField("b")
//typeOfB represents B<String>
ParameterizedType typeOfB = (ParameterizedType) GenericTypeReflector.getExactFieldType(b, typeOfA);
System.out.println(typeOfB.getActualTypeArguments()[0]); //String again
因此,您在这里要做的是从StringConsumer
开始,获取其字段a
(typeOfA
,即A<String, String>
)的类型,然后使用该信息来获取字段类型b
(typeOfB
,即B<String>
)。
通过这种方式,您可以根据需要进行进一步的操作...
答案 1 :(得分:0)
准确给出所发布的代码,在这种情况下可以确定type参数。以下示例中的方法进行了一些假设,并且不进行任何错误或健全性检查,而仅用于显示导致所需类型信息的“路径”:
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
class A<T>
{
B<T> b;
}
class B<T>
{
T t;
}
class StringConsumer
{
A<String> a;
}
class LongConsumer
{
A<Long> a;
}
public class GenericTypeReflectionTest
{
public static void main(String[] args) throws Exception
{
StringConsumer s = new StringConsumer();
LongConsumer t = new LongConsumer();
System.out.println(determineConsumedType(s));
System.out.println(determineConsumedType(t));
}
private static Class<?> determineConsumedType(Object object) throws Exception
{
Class<?> c = object.getClass();
Field field = c.getDeclaredField("a");
Type genericType = field.getGenericType();
ParameterizedType parameterizedType = (ParameterizedType)genericType;
Type[] typeArguments = parameterizedType.getActualTypeArguments();
Type consumedType = typeArguments[0];
return (Class<?>) consumedType;
}
}
(附带说明:在先前的评论中,我说过由于type erasure而无法实现。但这不是这种情况:顶级类是 not < / em>用Consumer<T>
或T==String
实例化的T==Long
,实际的类型信息保留在类的 field 中,明确声明要使用String
和Long
进行参数化,这就是为什么可以获得参数化类型的实际类型实参的原因,它们不是TypeVariable
对象,而是实际的{{1 }}对象)