如何使用reflection获取参数类型?

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

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

例:

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

我的类包含一个带签名的方法

 public foo(boolean, Collection, Number) 

我无法直接将参数映射到参数类型,因为我只是不知道哪个超类或接口是参数类型,如下表所示:

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

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

 // 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; } } 

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

 private static final Map> methodCache; 

并添加这样的查找方法:

 public static Set getMatchingMethods(final Class clazz, final Object[] args) throws Exception{ final String cacheKey = toCacheKey(clazz, args); Set methods = methodCache.get(cacheKey); if(methods == null){ final Set tmpMethods = new HashSet(); 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(); } 

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

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

  1. 生成缓存密钥并查询HashMap或
  2. 迭代所有方法并查询参数兼容性

我猜:对于大class(很多方法),第一种方法会胜出,否则第二种方法会胜出