如何使用reflection获取参数类型?
我想使用具有不同数量参数的函数。 问题是我不知道每个函数的参数数量,而且我不知道函数的名称,因为它们存储在数组中。 我只知道类名,但不想使用getDeclaredMethods
因为它会增加搜索时间。 有没有办法获取每个函数的参数类型?
当我必须查找方法时,我通常做的是从我正在进行的查询生成缓存键,并将此缓存键保存在地图中。
例:
我知道方法参数是Boolean.TRUE
, Arrays.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()
在内部使用缓存,所以问题在于我的缓存是否会提高性能。 这基本上是一个更快的问题:
- 生成缓存密钥并查询HashMap或
- 迭代所有方法并查询参数兼容性
我猜:对于大class(很多方法),第一种方法会胜出,否则第二种方法会胜出
- Tomcat 7强制取消注册JDBC驱动程序,为什么?
- 可能的Javagenerics(模板)专业化(覆盖具有特定类型的模板类型)
- 为什么这个未处理的org.apache.tiles.impl.CannotRenderException?
- 如何为CompletableFuture :: supplyAsync选择Executor
- 获取数组类型的Class对象的最佳方法是什么?
- war文件大小是否以某种方式影响应用程序和/或应用程序服务器的性能?
- Maven通过systemPath / system添加jar,但不添加到war或其他任何地方
- 在classpath中打印spring.xml的路径
- 如何在Java中实现==运算符?