我想使用具有不同參數數量的函數。問題是我不知道每個函數的參數數量,也不知道函數的名稱,因爲它們存儲在一個數組中。我只知道班級名稱,但不想使用getDeclaredMethods
,因爲它會增加搜索時間。有沒有辦法爲每個函數獲取參數類型?如何使用反射獲取參數類型?
8
A
回答
4
當我必須查找方法時,我通常會做的是從查詢中生成一個緩存鍵,並將該緩存鍵的搜索結果保存在地圖中。
例子:
我知道方法參數Boolean.TRUE
,Arrays.asList("foo","bar","baz")
和BigInteger.valueOf(77777l)
我的類包含與簽名的方法
public foo(boolean, Collection, Number)
有沒有辦法,我可以將參數直接映射參數類型,因爲我只是不知道哪個超類或接口是參數類型,如下表所示:
這些對每一個是兼容的,但是沒有辦法找到兼容的方法沒有定義的比較方法,像這樣:
// 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<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();
}
這樣,隨後的查找將比第一個查找花費更少的時間(對於相同類型的參數)。
當然,因爲Class.getDeclaredMethods()
在內部使用緩存,所以問題是我的緩存是否改善了性能。它基本上是一個什麼樣的速度更快問題:
- 生成緩存鍵和查詢一個HashMap或
- 遍歷所有的方法和查詢參數兼容性
我的猜測:大班(許多方法),第一種方法將獲勝,否則第二種方法將
相關問題
- 1. 如何使用java反射獲取類型參數值?
- 2. 使用scala獲取方法參數類型2.10反射API
- 3. 使用反射獲取MemberInfo的類型
- 4. 使用反射獲取類型
- 5. 獲取容器類型使用反射
- 6. 如何使用反射來獲取字段的類型?
- 7. 如何使用Java反射從ParameterizedType獲取GenericDeclaration的類型?
- 8. C#反射 - 投射參數到類型
- 9. 如何確定使用反射基類的泛型參數
- 10. PHP反射 - 獲取方法參數類型爲字符串
- 11. 如何獲取使用反射的方法的參數
- 12. 如何使用Java反射獲取參數名稱
- 13. 使用反射獲取所有Integer數據類型字段
- 14. Java:在嵌套參數化類型中獲取內部類型(反射)
- 15. 使用反射獲取參數的參數
- 16. Php在Hack中使用反射獲取泛型類型
- 17. 反射獲取FieldInfo對象的類型?
- 18. 從反射獲取實際類型fieldInfo
- 19. ObservableArrayList:如何通過反射獲取通用類型?
- 20. 使用反射來獲取靜態類
- 21. 使用反射來獲取類描述
- 22. 使用Java反射類獲取方法
- 23. 使用反射獲取類變量值
- 24. 使用反射獲取類方法
- 25. 如何使用反射來獲取擴展方法上泛型類型
- 26. 如何獲取泛型方法參數的類型參數類?
- 27. 如何通過反射來獲取和使用類/實體類型?
- 28. 使用反射比較通用參數類型
- 29. 如何使用非泛型參數調用方法(反射)?
- 30. 通過反射獲取事件參數
*,因爲它們存儲在一個數組*誰是'他們'?方法或參數?請展示一些代碼來說明 – 2011-02-11 09:52:05