如何使用反射获取参数类型?

编程入门 行业动态 更新时间:2024-10-24 16:21:18
本文介绍了如何使用反射获取参数类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我想使用具有不同数量参数的函数。问题是我不知道每个函数的参数数量,而且我不知道函数的名称,因为它们存储在数组中。我只知道类名,但不想使用 getDeclaredMethods 因为它会增加搜索时间。有没有办法获取每个函数的参数类型?

I want to use functions having different numbers of parameters. The problem is that I don't know the number of parameters of each function, and also I don't know names of function as they are stored in an array. I only knows the class name, but don't want to use getDeclaredMethods as it will increase search time. Is there a way to get the parameter types for each function?

推荐答案

我必须查找方法时通常做的是从我正在进行的查询生成缓存键,并将此缓存键保存在地图中的搜索结果。

What I usually do when I have to look up methods is to generate a cache key from the query I am doing and save the search result with this cache key in a map.

示例:

我知道方法参数是 Boolean.TRUE , Arrays.asList(foo,bar,baz )和 BigInteger.valueOf(77777l)

I know the method parameters are Boolean.TRUE, Arrays.asList("foo","bar","baz") and BigInteger.valueOf(77777l)

我的类包含一个方法签名

My class contains a method with the signature

public foo(boolean, Collection, Number)

我无法直接将参数映射到参数类型,因为我只是不知道哪个超类或接口是参数类型,你可以从中看到下表:

There's no way I can directly map the parameters to the parameter types because I just don't know which of the super classes or interfaces is the parameter type as you can see from the following table:

Expected Type | What I have ----------------------------------------------------- boolean | java.lang.Boolean java.util.Collection | java.util.Arrays$ArrayList java.lang.Number | java.math.BigInteger

这些对中的每一对都是兼容的,但是无法找到兼容的方法没有定义比较方法,如下所示:

Each of these pairs is compatible, but there's no way to find the compatible method without defining a comparison method, something like this:

// determine whether a method's parameter types are compatible // with my arg array public static boolean isCompatible(final Method method, final Object[] params) throws Exception{ final Class<?>[] parameterTypes = method.getParameterTypes(); if(params.length != parameterTypes.length){ return false; } for(int i = 0; i < params.length; i++){ final Object object = params[i]; final Class<?> paramType = parameterTypes[i]; if(!isCompatible(object, paramType)){ return false; } } return true; } // determine whether a single object is compatible with // a single parameter type // careful: the object may be null private static boolean isCompatible(final Object object, final Class<?> paramType) throws Exception{ if(object == null){ // primitive parameters are the only parameters // that can't handle a null object return !paramType.isPrimitive(); } // handles same type, super types and implemented interfaces if(paramType.isInstance(object)){ return true; } // special case: the arg may be the Object wrapper for the // primitive parameter type if(paramType.isPrimitive()){ return isWrapperTypeOf(object.getClass(), paramType); } return false; } /* awful hack, can be made much more elegant using Guava: return Primitives.unwrap(candidate).equals(primitiveType); */ private static boolean isWrapperTypeOf(final Class<?> candidate, final Class<?> primitiveType) throws Exception{ try{ return !candidate.isPrimitive() && candidate .getDeclaredField("TYPE") .get(null) .equals(primitiveType); } catch(final NoSuchFieldException e){ return false; } catch(final Exception e){ throw e; } }

所以我要做的是有一个方法缓存:

So what I'd do is have a method cache:

private static final Map<String, Set<Method>> methodCache;

并添加如下查找方法:

public static Set<Method> getMatchingMethods(final Class<?> clazz, final Object[] args) throws Exception{ final String cacheKey = toCacheKey(clazz, args); Set<Method> methods = methodCache.get(cacheKey); if(methods == null){ final Set<Method> tmpMethods = new HashSet<Method>(); for(final Method candidate : clazz.getDeclaredMethods()){ if(isCompatible(candidate, args)){ tmpMethods.add(candidate); } } methods = Collections.unmodifiableSet(tmpMethods); methodCache.put(cacheKey, methods); } return methods; } private static String toCacheKey(final Class<?> clazz, final Object[] args){ final StringBuilder sb = new StringBuilder(clazz.getName()); for(final Object obj : args){ sb.append('-').append( obj == null ? "null" : obj.getClass().getName()); } return sb.toString(); }

这样,后续查找所花的时间比第一次少得多(对于相同类型的参数)。

That way, subsequent lookups will take much less time than the first one (for parameters of the same type).

当然,因为 Class.getDeclaredMethods()在内部使用缓存,所以问题是我的缓存是否提高了性能。这基本上是一个更快的问题:

Of course since Class.getDeclaredMethods() uses a cache internally, the question is whether my cache improves performance at all. It's basically a question of what's faster:

  • 生成缓存密钥并查询HashMap或
  • 迭代所有方法并查询参数兼容性
  • 我的猜测:对于大类(许多方法),第一种方法将获胜,否则第二个将

    My guess: for large classes (many methods), the first method will win, otherwise the second will

    更多推荐

    如何使用反射获取参数类型?

    本文发布于:2023-11-11 18:35:46,感谢您对本站的认可!
    本文链接:https://www.elefans.com/category/jswz/34/1579247.html
    版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
    本文标签:如何使用   反射   参数   类型

    发布评论

    评论列表 (有 0 条评论)
    草根站长

    >www.elefans.com

    编程频道|电子爱好者 - 技术资讯及电子产品介绍!