java - 如何获取形式方法参数类型的实参?

标签 java reflection guava type-erasure

我有带有 Event<Something> 类型的单个参数的方法并且需要提取 Something或其原始类型。它可能看起来像

 void method1(Event<MyEnum1> event) {}
 <E extends Enum<E>> method2(Event<E> event) {}
 <K, V> method3(Event<Map<K, V>> event) {}

我想要一个函数映射

method1 -> MyEnum.class
method2 -> Enum.class
method3 -> Map.class

对于method1 ,很容易使用(ParameterizedType) method.getGenericParameterTypes() 。对于 method2 ,我可以使用 Guava

TypeToken.of(method.getDeclaringClass())
    .method(method)
    .getTypeParameters()[0]
    .getBounds()

获得Type

TypeToken.of(method.getDeclaringClass())
    .method(method)
    .getParameters()
    .get(0)

获取Parameter 。我想,我需要解决 Parameter使用Type ,但我被困在这里了。

我不太关心method3 ,尽管了解一般方法会很好。我不关心实际参数的类型(我知道删除)。

最佳答案

您不需要TypeToken为了这。 java.lang.reflect提供您需要的一切。

您需要考虑多种情​​况。我假设提供的任何方法的第一个参数始终为 Event 类型(或者实际上是参数化类型)。

您需要处理 Type 的 5 个子类型。从您的示例中,您需要检查类型参数是否是具体类型( MyEnum )、类型变量( EEnum 为界)或参数化类型( Map<K,V> )。

此外,还有WildcardType您可以像处理类型变量一样处理它并提取边界。最后,您必须使用 GenericArrayType 处理通用数组类型。 ( Event<T[]>Event<List<String>[]> )。我已经忽略了这些,但它只是对其他类型重新应用相同的规则。

我假设,对于类型变量的情况,边界可能是其他类型变量,因此我们需要递归,直到找到具体的边界。

// get raw type argument of first parameter
public static Class<?> getRawTypeArgument(Method method) {
    Parameter parameter = method.getParameters()[0];
    Type type = parameter.getParameterizedType();
    /// assume it's parameterized
    ParameterizedType parameterizedType = (ParameterizedType) type;
    // assume there's one type argument
    Type typeArgument = parameterizedType.getActualTypeArguments()[0];
    if (typeArgument instanceof TypeVariable<?>) {
        TypeVariable<?> typeVariableArgument = (TypeVariable<?>) typeArgument;
        return recursivelyExtractBound(typeVariableArgument);
    } else if (typeArgument instanceof Class<?>) {
        return (Class<?>) typeArgument;
    } else if (typeArgument instanceof ParameterizedType) {
        ParameterizedType parameterizedTypeArgument = (ParameterizedType) typeArgument;
        return (Class<?>) parameterizedTypeArgument.getRawType();
    } 
    throw new AssertionError("Consider wildcard and generic type");
}

private static Class<?> recursivelyExtractBound(TypeVariable<?> typeVariable) {
    // assume first
    Type bound = typeVariable.getBounds()[0];
    if (bound instanceof Class<?>) {
        return (Class<?>) bound;
    } else if (bound instanceof TypeVariable<?>) {
        TypeVariable<?> nested = (TypeVariable<?>) bound;
        return recursivelyExtractBound(nested);
    } else if (bound instanceof ParameterizedType) {
        ParameterizedType parameterizedTypeArgument = (ParameterizedType) bound;
        return (Class<?>) parameterizedTypeArgument.getRawType();
    }
    throw new AssertionError("Are there others?");
}

带有一个小驱动程序

public static void main(String[] args) throws Exception {
    Class<?> clazz = Example.class;
    for (Method method : clazz.getDeclaredMethods()) {
        if (!method.getName().startsWith("method")) {
            continue;
        }
        System.out.println("Method '" + method + "' -> " + getRawTypeArgument(method));
    }
}

打印出上面的内容

Method 'java.lang.Object com.example.Example.method3(com.example.root.Event)' -> interface java.util.Map
Method 'java.lang.Object com.example.Example.method2(com.example.root.Event)' -> class java.lang.Enum
Method 'void com.example.Example.method1(com.example.Event)' -> class com.example.MyEnum1

关于java - 如何获取形式方法参数类型的实参?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44999985/

相关文章:

java - jclouds:创建 BlobStoreContext 时如何提供自己的 KeyStore

iphone - 如何使用 plist NSString 项作为 UIImageView 对象名称

language-agnostic - 为什么反射(reflection)叫反射而不叫内省(introspection)呢?

java - ClassPath.getTopLevelClasses() 应该返回 `java.*` 包吗?

java - Scala - 当模式匹配 boolean 值和默认值时无法访问代码

java - 警告 : No mapping found for HTTP request with URI [/SpringLoginApplication/] in DispatcherServlet with name 'SpringLoginApplication'

java - 对于Android应用程序来说,c#好还是java好?

php - 如何从特定的 PDO 驱动程序对象中获取所有方法的完整列表?

java - 通过拆分和运行将 ListenableFuture<Iterable<A>> 转换为 Iterable<ListenableFuture<B>>

java - 如何使用 guava FluentIterable 来简化 map 转换?