MST

星途 面试题库

面试题:Java泛型反射在处理复杂嵌套泛型结构时的难题及解决方法

假设有一个复杂的嵌套泛型结构`class Outer<T>{ class Inner<U>{} }`,并且有实例`Outer<List<String>> outer = new Outer<>(); Outer.Inner<Integer> inner = outer.new Inner<>();`,请阐述使用反射获取`outer`和`inner`的泛型类型时会遇到哪些难题,以及如何解决这些难题。
47.3万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

难题

  1. 获取Outer的泛型类型参数:虽然outerOuter<List<String>>的实例,但通过普通反射获取泛型信息时,在运行时泛型类型信息会被擦除,无法直接获取到<List<String>>这种精确的泛型类型,只能获取到原始类型Outer
  2. 获取Inner的泛型类型参数:对于inner,同样存在泛型类型擦除问题。并且Inner是嵌套类,获取其泛型类型不仅要克服类型擦除,还要处理嵌套结构带来的复杂性,常规反射难以直接获取到<Integer>这个泛型参数。

解决方案

  1. 使用ParameterizedType接口
    • 要获取Outer的泛型类型,可以通过获取声明outer变量的字段或方法的泛型类型来间接获取。假设outer是在某个类的字段中声明,可以通过如下代码:
Field field = OuterContainer.class.getDeclaredField("outer");
Type genericType = field.getGenericType();
if (genericType instanceof ParameterizedType) {
    ParameterizedType parameterizedType = (ParameterizedType) genericType;
    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
    if (actualTypeArguments.length > 0) {
        Type outerActualType = actualTypeArguments[0];
        // 这里outerActualType就是List<String>的Type,还可以进一步处理
    }
}
- 对于`Inner`,由于`Inner`是`Outer`的内部类,先获取`Outer`的类型,再获取`Inner`的构造函数的泛型类型。假设通过反射创建`Inner`实例:
Constructor<Outer.Inner> constructor = Outer.class.getDeclaredInnerClass("Inner").getConstructor();
Type genericReturnType = constructor.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType) {
    ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
    if (actualTypeArguments.length > 0) {
        Type innerActualType = actualTypeArguments[0];
        // 这里innerActualType就是Integer的Type
    }
}
  1. 利用TypeToken类(Guava库):Guava库中的TypeToken类能更方便地处理泛型类型。例如:
TypeToken<Outer<List<String>>> outerToken = new TypeToken<Outer<List<String>>>() {};
Type outerType = outerToken.getType();
// 处理outerType获取具体泛型信息

TypeToken<Outer.Inner<Integer>> innerToken = new TypeToken<Outer.Inner<Integer>>() {};
Type innerType = innerToken.getType();
// 处理innerType获取具体泛型信息

通过这种方式,可以在编译时保留泛型信息,从而在运行时准确获取泛型类型。