【问题标题】:How to convert Type with generics into a Class in java?java - 如何将带有泛型的Type转换为Java中的Class?
【发布时间】:2018-01-02 09:44:51
【问题描述】:

我有一个方法对象。

我想用泛型提取返回 Type 并将其转换为 Class 以便将此类信息传递给 Spring PropertyResolver

Type type = myMethod.getGenericReturnType();
Class<?> returnType = /* ??? */;
environment.getProperty(key, returnType);

【问题讨论】:

  • 你看过这个了吗? stackoverflow.com/questions/3403909/…
  • 既然getProperty只接受Class参数,为什么不直接使用myMethod.getReturnType()呢?
  • @AndyTurner 我这样做会丢失泛型信息
  • @pixel 但是由于getProperty 只接受Class 参数- 并且没有List&lt;String&gt;.class 这样的东西,例如,只有List.class - 你会怎么做呢?跨度>
  • @AndyTurner 你是对的 - 我需要做一些更复杂的事情才能用泛型转换价值。我发现这段代码正在做类似于我想要实现的事情:github.com/lviggiano/owner/blob/master/owner/src/main/java/org/…

标签: java generics reflection types spring-properties


【解决方案1】:

在实践中,返回 Type 实例必须是以下之一:Class(例如 String)、GenericArrayType(例如 String[]T[]List&lt;T&gt;[])、TypeVariable(例如T) 或ParametrizedType(例如List&lt;String&gt;List&lt;T&gt;)。另外Type也可以是WildcardType(例如List&lt;?&gt;中的?)但是这些不能直接用作返回类型。

下面的代码尝试根据这 5 个中的子接口解析给定实例的类。很少有 Type 不会扩展 5 个中的任何一个,在这种情况下,我们只是说我们不能继续使用 @ 987654338@。例如,您可以创建自己的合成 Type 扩展类,但您为什么要这样做?

public static Class<?> type2Class(Type type) {
    if (type instanceof Class) {
       return (Class<?>) type;
    } else if (type instanceof GenericArrayType) {
       // having to create an array instance to get the class is kinda nasty 
       // but apparently this is a current limitation of java-reflection concerning array classes.
       return Array.newInstance(type2Class(((GenericArrayType)type).getGenericComponentType()), 0).getClass(); // E.g. T[] -> T -> Object.class if <T> or Number.class if <T extends Number & Comparable>
    } else if (type instanceof ParameterizedType) {
       return type2Class(((ParameterizedType) type).getRawType()); // Eg. List<T> would return List.class
    } else if (type instanceof TypeVariable) {
       Type[] bounds = ((TypeVariable<?>) type).getBounds();
       return bounds.length == 0 ? Object.class : type2Class(bounds[0]); // erasure is to the left-most bound.
    } else if (type instanceof WildcardType) {
       Type[] bounds = ((WildcardType) type).getUpperBounds();
       return bounds.length == 0 ? Object.class : type2Class(bounds[0]); // erasure is to the left-most upper bound.
    } else { 
       throw new UnsupportedOperationException("cannot handle type class: " + type.getClass());
    }
} 

请注意,代码未经测试,因此可能包含编译错误。此外,我不确定GenericArrayType 将如何处理像T[][] 这样的多维数组类型(如果&lt;T&gt;,它可能会返回Object[] 而不是Object[][],所以我们需要在这里做额外的工作)。如果需要更正,请告诉我。

最后,我们在这里要做的是计算给定 Type 的 Erasure 类我想知道是否有一些“标准”代码可以做到这一点,也许是 Sun/Oracle 编译器或代码分析器工具的一部分而且您只需使用它们的实用程序,就可以省去编码和维护它的麻烦......我没有通过快速浏览找到任何东西。

【讨论】:

    【解决方案2】:

    您可以使用变通方法将Method.getGenericReturnType() 返回的java.lang.reflect.Type 转换为泛型的Class

    字符串解析:

    final String typeName = method.getGenericReturnType().getTypeName();
    Pattern pattern = Pattern.compile("<(.*)>");
    final Matcher matcher = pattern.matcher(typeName);
    if (matcher.find()) {
        String className = matcher.group(1);
        Class<?> clazz = Class.forName(className);        
    }
    

    您也可以将java.lang.reflect.Type 向下转换为运行时使用的具体类:sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl,但我想它可能会根据 JVM 发生变化。

    final Type genericReturnType = method.getGenericReturnType();
    sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl typeImpl = (ParameterizedTypeImpl) genericReturnType;
    String className = typeImpl.getActualTypeArguments()[0].getTypeName();
    Class<?> clazz = Class.forName(className);
    

    【讨论】:

    • 你解开 type 参数而不是 rawType 有什么原因吗?
    • 这不是 OP 要求的吗?可能我理解错了。
    猜你喜欢
    • 2018-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-22
    • 2016-03-31
    • 1970-01-01
    相关资源
    最近更新 更多