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

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

例:

我知道方法参数是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或

>迭代所有方法并查询参数兼容性

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

你可能感兴趣的:(java,反射,参数类型)