简体   繁体   English

Java 反思:如何获取Class的实例<t>来自 ParameterizedType.getActualTypeArguments() 数组?</t>

[英]Java Reflection: How to obtain an instance of Class<T> from the ParameterizedType.getActualTypeArguments() array?

What I'm trying to do is to get a generic typearg of a Field using我想要做的是使用一个 Field 的通用 typearg

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

(where f is an instance of java.lang.Field ). (其中fjava.lang.Field的一个实例)。 I need that instance of Class<?> to perform a Foo.class.isAssignableFrom(typearg0) check later, which only takes Class<T> es as an argument.我需要Class<?>的实例来执行Foo.class.isAssignableFrom(typearg0)检查,它只需要Class<T> es作为参数。 At the same time, I know (or expect) said typearg0 to be a parameterized type as well , so there's a contradiction: typearg0 cannot be Class<?> and ParameterizedType at the same time, because Class<?> is itself a class and does not implement ParameterizedType .同时,我知道(或期望)说typearg0也是参数化类型因此存在矛盾: typearg0不能同时是Class<?>ParameterizedType ,因为Class<?>本身就是 class 和不实现ParameterizedType

Can I achieve the isAssignableFrom() check in any other way?我可以以任何其他方式实现isAssignableFrom()检查吗? Or is my goal generally impossible to achieve?或者我的目标通常是不可能实现的?

Thank you very much!非常感谢!

Edit:编辑:

Here is an example:这是一个例子:

Suppose you expect a Field of type Map<Foo, Set<Bar>> , but all you got is a java.lang.reflect.Field instance.假设您期望Map<Foo, Set<Bar>>类型的 Field,但您得到的只是java.lang.reflect.Field实例。 Now, you don't want it to precisely match Map<Foo, Set<Bar>> , you just want the respective types to be instances of Map or Set .现在,您不希望它精确匹配Map<Foo, Set<Bar>> ,您只希望各自的类型是MapSet实例 It is not a rigid specification check, it's more of a "sanity check".这不是严格的规范检查,更像是“健全性检查”。 I would attempt this check like this:我会尝试这样的检查:

  1. Get the field type as a class ( .getType() )获取字段类型为 class ( .getType() )
  2. Check whether Map is assignable from the field type检查Map是否可从字段类型分配
  3. Get the field type as a (possibly) parameterized type ( .getGenericType() )将字段类型作为(可能)参数化类型( .getGenericType()
  4. Check that the first generic parameter is Foo (this should be an exact match)检查第一个泛型参数是否为Foo (这应该是完全匹配的)
  5. Get the second generic parameter as a class获取第二个通用参数作为 class
  6. Check whether Set is assignable from this nested type检查Set是否可以从此嵌套类型分配
  7. Check whether the nested type is itself a ParameterizedType and cast it检查嵌套类型本身是否为ParameterizedType并强制转换
  8. Check that the first generic parameter of the nested type is Bar (this should be an exact match)检查嵌套类型的第一个泛型参数是否为Bar (这应该是完全匹配的)

However, I don't know how to achieve 5 and/or 6.但是,我不知道如何达到 5 和/或 6。

(using java 11) (使用 java 11)

Just like you've done with Map , Set is likely to be an instance of ParameterizedType so you can check it and then cast it.就像您对Map所做的一样, Set很可能是ParameterizedType的一个实例,因此您可以检查它然后进行转换。

From that ParameterizedType (which represents the Set<Something> ), you can get use getRawType to get a Set .从那个ParameterizedType (代表Set<Something> ),您可以使用getRawType来获取Set That's a Type too -- but this should be safely castable to Class .这也是一个Type ——但这应该可以安全地转换为Class Just in case it's not, you can use a fallback and load the class using its name.以防万一,您可以使用后备并使用其名称加载 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*/ }

Here's a full 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";
    }
}

Output: Output:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何使用Java反射检查ParameterizedType参数是否扩展了特定的类 - How to use Java reflection to check if ParameterizedType argument extends a specific class 如何使用Java Reflection从ParameterizedType获取GenericDeclaration的类型? - How to get the Type of GenericDeclaration from ParameterizedType using Java Reflection? 如何在Java中获取ParameterizedType的通用容器类 - How to get generic container class of a ParameterizedType in java 如何使用Java反射从字段中获取扩展类的匿名实例? - How to get an anonymous instance that extends a class from a field with java reflection? 在这种情况下,`ParameterizedType#getActualTypeArguments` 返回一个包含多个元素的数组 - In which case `ParameterizedType#getActualTypeArguments` return an array which has more than one elements 类强制转换异常泛型反射ParameterizedType - Class Cast Exception Generics Reflection ParameterizedType 从类的“数组版本”到在 Java 中具有反射的类 - from "array version" of a class to the class with reflection in java Java ClassCastException从通用实例“ new ClazzXXX”中获取ParameterizedType E <E> ()” - Java ClassCastException taking ParameterizedType E from generic instance “new ClazzXXX<E>()” Java 反射 - 从 class 实例字段获取值 - Java reflection - Get values from class instance field 如何在Java中通过反射获得pirvate内部类实例? - How to get pirvate inner class instance with reflection in Java?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM