说我有这些课程:
class Container<T> {
private List<T> list;
}
我有一个Container
的实例,比如说
Container<?> instance = new Container<String>();
有没有办法在运行时找出list
的实际类型参数?即,它是 List
的String
,而不是 List
的java.lang.reflect.TypeVariable
。< / p>
我一直在关注Java的反思(field.getGenericType()
),各种图书馆(Guava Reflect,Typetools,ClassMate,甚至是{{3等等)但我无法弄清楚。
我无法控制Container
类型,因此我无法为其添加任何字段。
我意识到由于擦除可能根本不可能,尽管我不介意弄乱字节码,如果可以的话。
编辑我过度简化了我的初步问题。我还有其他信息;我也有这种类型:
class StringContainerContainer {
private Container<String> container;
}
(还有更多类似的类型,用于不同的通用参数。)
在运行时,我给出了上面提到的instance
个对象。通过对我的代码库进行一些重构,我还可以访问StringContainerContainer
类(或与*ContainerContainer
类相关的类),我可以使用它来获取java.lang.reflect.Field
container
}。
答案 0 :(得分:2)
由于类型擦除,你不能这样做。使用反射可以做的最多的事情是获取有关声明的类型变量的信息,而不是运行时实例绑定的实际类型。编译器抛弃了这些信息。
有关详情,请参阅tutorial on Type Erasure和/或section 4.6 of the Java Language Specification,其中讨论了类型擦除。
如果您需要有关实例类的运行时类型信息,那么您可以做的最好是要求在实例构造中传递Class
对象:
class Container<T> {
private List<T> list;
private Class<T> type;
public Container(Class<T> type) {
this.type = type;
}
}
答案 1 :(得分:2)
使用您的编辑,是的,您可以发现String
是实际的类型参数:
Field field = StringContainerContainer.class.getDeclaredField("container");
ParameterizedType gt = (ParameterizedType) field.getGenericType();
Class<?> arg = (Class<?>) gt.getActualTypeArguments()[0];
System.out.println(arg);
我应该指出,这标识了container
的{{1}}字段的类型参数。鉴于如何编写StringContainerContainer
,它也恰好是其Container
字段的类型参数,但不直接检查该字段。