解析 TypeVariable

Resolve a TypeVariable

假设我有这些 classes:

class Container<T> {
  private List<T> list;
}

我有一个 Container 的实例,比如

Container<?> instance = new Container<String>();

有没有办法找出 list 在 运行 时的实际类型参数?也就是说,它是 StringList,而不是 java.lang.reflect.TypeVariableList ].

我一直在查看 Java 的反射(field.getGenericType())、各种库(Guava Reflect, Typetools, ClassMate, even ASM 等),但我无法弄清楚。

我无法控制 Container 类型,因此无法向其添加任何字段。

我意识到由于擦除,这可能根本不可能,但如果可能的话,我不介意弄乱字节码。

编辑 我过度简化了我最初的问题。我有一条额外的信息可用;我也有这种:

class StringContainerContainer {
  private Container<String> container;
}

(还有更多类似的类型,用于不同的通用参数。)

在 运行 时,我得到了上面提到的 instance 对象。通过对我的代码库进行一些重构,我还可以得到 StringContainerContainer class(或任何相关的 *ContainerContainer class),我可以用它来获得 java.lang.reflect.Field 对于 container.

由于类型擦除,你不能这样做。使用反射最多只能获取有关已声明类型变量的信息,而不是在 运行 时间由实例绑定的实际类型。该信息被编译器丢弃。

有关详细信息,请阅读讨论类型擦除的 tutorial on Type Erasure and/or section 4.6 of the Java Language Specification

如果您需要 run-time 有关实例的类型信息 class,您最好的办法是要求在实例构造时传递一个 Class 对象:

class Container<T> {
    private List<T> list;
    private Class<T> type;

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

通过你的编辑,是的,你可以发现 String 是实际的类型参数:

Field field = StringContainerContainer.class.getDeclaredField("container");
ParameterizedType gt = (ParameterizedType) field.getGenericType();
Class<?> arg = (Class<?>) gt.getActualTypeArguments()[0];
System.out.println(arg);

我应该指出,这标识了 StringContainerContainercontainer 字段的类型参数。鉴于 Container 的编写方式,这也恰好是其 list 字段的类型参数,但该字段未被直接检查。