【问题标题】:Java Reflection: How to obtain an instance of Class<T> from the ParameterizedType.getActualTypeArguments() array?Java 反射:如何从 ParameterizedType.getActualTypeArguments() 数组中获取 Class<T> 的实例?
【发布时间】:2021-05-20 16:41:06
【问题描述】:

我想要做的是使用一个字段的通用类型参数

Type type = f.getGenericType();
if (type instanceof ParameterizedType) {
    ParameterizedType ptype = (ParameterizedType) type;
    // ...
    Class<?> typearg0 = ??? // ptype.getActualTypeArguments()[0]
}

(其中fjava.lang.Field 的一个实例)。我需要Class&lt;?&gt; 的实例稍后执行Foo.class.isAssignableFrom(typearg0) 检查,它只将Class&lt;T&gt;es 作为参数。同时,我知道(或期望)说typearg0 也是参数化类型以及,所以有一个矛盾:typearg0 不能同时是Class&lt;?&gt;ParameterizedType时间,因为Class&lt;?&gt;本身是一个类,并没有实现ParameterizedType

我可以通过其他方式实现isAssignableFrom() 检查吗?还是我的目标通常无法实现?

非常感谢!

编辑:

这是一个例子:

假设您期望一个类型为Map&lt;Foo, Set&lt;Bar&gt;&gt; 的字段,但您得到的只是一个java.lang.reflect.Field 实例。现在,您不希望它精确匹配Map&lt;Foo, Set&lt;Bar&gt;&gt;,您只希望各自的类型是MapSet实例。这不是严格的规范检查,更像是“健全性检查”。我会尝试这样的检查:

  1. 以类的形式获取字段类型 (.getType())
  2. 检查Map是否可以从字段类型中赋值
  3. 将字段类型获取为(可能)参数化类型 (.getGenericType())
  4. 检查第一个泛型参数是否为Foo(这应该是完全匹配的)
  5. 获取第二个泛型参数作为类
  6. 检查 Set 是否可以从此嵌套类型中赋值
  7. 检查嵌套类型本身是否为 ParameterizedType 并强制转换
  8. 检查嵌套类型的第一个泛型参数是Bar(这应该是完全匹配)

但是,我不知道如何达到 5 和/或 6。

(使用 java 11)

【问题讨论】:

  • 这能回答你的问题吗? stackoverflow.com/questions/38761897/…
  • 你的例子可能更清楚一个具体的例子。我想您拥有的字段类似于List&lt;Set&lt;String&gt;&gt;,并且您想要Set.class 位(反射性地),因此您可以执行Foo.class.isAssignableFrom(Set.class)。对吗?
  • @Michael 完全正确,但我将添加一个示例以进行澄清
  • 原帖已编辑

标签: java generics reflection


【解决方案1】:

就像你对Map 所做的那样,Set 很可能是ParameterizedType 的一个实例,所以你可以检查它然后再转换它。

ParameterizedType(代表Set&lt;Something&gt;),您可以使用getRawType 获得Set。那也是Type——但这应该可以安全地转换为Class。万一不是,您可以使用后备并使用其名称加载类。

final Type valueType = mapType.getActualTypeArguments()[1];
final ParameterizedType pValueType = (ParameterizedType) valueType;
final Class<?> valueClass = pValueType.getRawType() instanceof Class ?
    ((Class<?>) pValueType.getRawType()) :
    // Should be castable, but just in case it's not, fallback
    getClass().getClassLoader().loadClass(
        pValueType.getRawType().getTypeName()
    );
if (Set.class.isAssignableFrom(valueClass)) { /* do something*/ }

这是完整的runnable example

class Foo {}
class Bar {}
interface MyValidMap extends Map<Foo, Set<Bar>> {}

public class Application {
    public final HashMap<Foo, HashSet<Bar>> good = null;
    public final Map<Foo, Set<Bar>> better = null;
    public final String notAMap = null;
    public final Map<String, Set<Bar>> badKey = null;
    public final Map<Foo, List<String>> badValue = null;
    public final Map<Foo, Set<String>> badSetElems = null;
    public final MyValidMap noTypeParamMap = null;

    public static void main(String[] args) throws Exception {
        for (Field field : Application.class.getFields()) {
            System.out.println(field.getName() + " - " + fieldMatches(field));
        }
    }

    private static String fieldMatches(Field mapField) throws Exception {
        if (!Map.class.isAssignableFrom(mapField.getType())) {
            return "Field is not a Map";
        }

        if (!(mapField.getGenericType() instanceof ParameterizedType)) {
            // We know it's a map, but it doesn't have type params. Probably something
            // like this: class MyStringMap implements Map<String, String>. You can do
            // something with getGenericInterfaces() but this seems so unlikely that
            // it could just be ignored.
            return "TODO";
        }

        final ParameterizedType mapType = (ParameterizedType) mapField.getGenericType();
        final Type keyType = mapType.getActualTypeArguments()[0];
        final Type valueType = mapType.getActualTypeArguments()[1];
        if (Foo.class != keyType) {
            return "Map's key type is not Foo";
        }

        if (!(valueType instanceof ParameterizedType)) {
            // Same problem as above. May be a Set without type params
            return "Map's value is (probably) not a Set";
        }

        final ParameterizedType pValueType = (ParameterizedType) valueType;
        final Class<?> valueClass = pValueType.getRawType() instanceof Class ?
            ((Class<?>) pValueType.getRawType()) :
            Application.class.getClassLoader().loadClass(
                pValueType.getRawType().getTypeName()
            );

        if (!Set.class.isAssignableFrom(valueClass)) {
            return "Map's value is not a Set";
        }

        final Type setElemType = pValueType.getActualTypeArguments()[0];
        if (setElemType != Bar.class) {
            return "Set's elements are not Bars";
        }
        return "Looks good";
    }
}

输出:

good - Looks good
better - Looks good
notAMap - Field is not a Map
badKey - Map's key type is not Foo
badValue - Map's value is (probably) not a Set
badSetElems - Set's elements are not Bars
noTypeParamMap - TODO

【讨论】:

  • 非常详细和有帮助的答案,非常感谢!您可以通过首先将其转换为参数化类型然后调用getRawType() 来检索嵌套类型的Class&lt;?&gt;,这一事实确实是我正在寻找的缺失链接。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-22
  • 2014-02-11
  • 1970-01-01
  • 1970-01-01
  • 2022-10-07
  • 2018-07-02
  • 1970-01-01
相关资源
最近更新 更多