请考虑以下代码段:
public class ReflectionTest {
public static void main(String[] args) {
ReflectionTest test = new ReflectionTest();
String object = new String("Hello!");
// 1. String is accepted as an Object
test.print(object);
// 2. The appropriate method is not found with String.class
try {
java.lang.reflect.Method print
= test.getClass().getMethod("print", object.getClass());
print.invoke(test, object);
} catch (Exception ex) {
ex.printStackTrace(); // NoSuchMethodException!
}
}
public void print(Object object) {
System.out.println(object.toString());
}
}
getMethod()
显然不知道可以将String
提供给期望Object
的方法(实际上,它的文档说它查找具有指定名称的方法和完全相同的形式参数类型)。
是否有一种直接的方法来反复查找方法,如getMethod()
,但考虑到多态性,以便上面的反射示例在查询print(Object)
时可以找到("print", String.class)
方法参数Δ
答案 0 :(得分:8)
建议使用Class.isAssignableFrom()
样本来查找print(String)
Method[] allMethods = c.getDeclaredMethods();
for (Method m : allMethods) {
String mname = m.getName();
if (!mname.startsWith("print") {
continue;
}
Type[] pType = m.getGenericParameterTypes();
if ((pType.length != 1)
|| !String.class.isAssignableFrom(pType[0].getClass())) {
continue;
}
}
答案 1 :(得分:1)
执行此操作的简单方法是通过java.beans.Statement或java.beans.Expression。是否所有这些硬码都适合你。
getMethod()显然没有意识到这一点 字符串可以被提供给方法 期待一个对象
'Unaware'是一种奇怪的方式。 getMethod()
遵守其规范。您必须提供形式参数,而不是实际参数的类型。
答案 2 :(得分:1)
仅供参考,我使用带有多个参数的反射来调用方法而不给出它们的类型。
public class MyMethodUtils {
/**
* Need to pass parameter classes
*/
public static Object invoke(Object invoker, String methodName, Object[] parameters, Class[] parameterClasses) throws Exception {
Method method = invoker.getClass().getMethod(methodName, parameterClasses);
Object returnValue = method.invoke(invoker, parameters);
return returnValue;
}
/**
* No need to pass parameter classes
*/
public static Object invoke(Object invoker, String methodName, Object[] parameters) throws Exception {
Method[] allMethods = invoker.getClass().getDeclaredMethods();
Object returnValue = null;
boolean isFound = false;
for (Method m : allMethods) {
String mname = m.getName();
if (!mname.equals(methodName)) {
continue;
}
Class[] methodParaClasses = m.getParameterTypes();
for (int i = 0; i < methodParaClasses.length; i++) {
Class<?> parameterClass = parameters[i].getClass();
Class<?> methodParaClass = methodParaClasses[i];
boolean isAssignable = methodParaClass.isAssignableFrom(parameterClass);
if (!isAssignable) {
continue;
}
}
returnValue = m.invoke(invoker, parameters);
isFound = true;
}
if (!isFound) {
throw new RuntimeException("Cannot find such method");
}
return returnValue;
}
}
样本使用:
MyMethodUtils.invoke(student, "setNameAndMarks", new Object[] { "John", marks }, new Class[] { String.class, Collection.class });
MyMethodUtils.invoke(student, "setNameAndMarks", new Object[] { "John", marks });
但是,对于方法invoke(Object invoker, String methodName, Object[] parameters)
,如果签名不明确,则可以调用错误的方法。例如,如果调用者有两种方法:
public void setNameAndMarks(String name, Collection<Integer> marks);
public void setNameAndMarks(String name, ArrayList<Integer> marks);
传递以下参数可能会调用错误的方法
setNameAndMarks("John", new ArrayList<Integer>());