问题描述
我正在玩反射并尝试根据方法名称和提供的参数动态调用最适合的方法。我编写了一个快速示例。给定方法名称和可接受的参数(或多个参数,最终),我可以确定要运行的正确方法吗?
正如你在这个例子中看到的......
public class Methods
{
public static void goober(Object o) {
System.out.println("Object");
}
public static void goober(Double d) {
System.out.println("Double");
}
public static void goober(double d) {
System.out.println("double");
}
}
import java.lang.reflect.Method;
public class MethodIDTester
{
public static void main(String[] args) {
Methods.goober(new Object()); //prints Object
Methods.goober(new Double(5.0)); //prints Double
Methods.goober(5.0); //prints double
Methods.goober(5); //prints double
Methods.goober(new Integer(5)); //prints Object
System.out.println();
invoker("Methods","goober",new Object()); //prints Object
invoker("Methods",new Double(5.0)); //prints Double
invoker("Methods",5.0); //prints Double - Not what I wanted
invoker("Methods",5); //prints NoSuchMethodException - Not what I wanted
invoker("Methods",new Integer(5)); //prints NoSuchMethodException - Not what I wanted
}
public static void invoker(String cName,String mName,Object param) {
try {
Class<?> c = Class.forName(cName);
Method m = c.getmethod(mName,param.getClass());
m.invoke(c,param);
} catch (Exception e) { System.out.println(e); }
}
}
如何改进我的调用程序,使其以与直接调用方法时 java 相同的方式将参数连接到正确的方法?
我希望参数 5.0 位于接收原始双精度值的方法中。
我希望它意识到原始 int 5 可以落在接收双精度值的方法中。
我希望它意识到 Integer 对象可以在接收 Object 对象的方法中着陆。
我很犹豫要不要尝试编写我自己的向上转换系统,因为我不一定知道 java 如何确定向上转换的优先级(尤其是当有多个参数时)。我想确保我的系统识别与编译器识别的方法相同的方法,这似乎很危险。我宁愿只问 java 它会使用哪种方法 bind 而不是试图自己弄清楚。有这样的东西吗?
解决方法
反射查找与方法的精确声明匹配,这就是为什么某些查找返回 NoSuchMethodException 的原因。如果找不到方法,您可以尝试查看超类。
GroupBy
对于调用者调用,double 值被自动装箱为 Double,因此处理 Double / double 情况的唯一方法是将调用者更改为提供 double.class。
要解决这两个问题,您可以添加 Method m = c.getMethod(mName,param.getClass());
来查找类,例如:
invoker()
那么:
public static void invoker(String cName,String mName,Object param) {
invoker(cName,mName,param.getClass(),param);
}
public static void invoker(String cName,Class<?> argC,Object param) {
try {
Class<?> c = Class.forName(cName);
System.out.println("invoker "+cName+"."+mName+"("+argC.getName()+") with param "+param);
Method m = c.getMethod(mName,argC);
m.invoke(c,param);
}
catch (NoSuchMethodException e) {
Class<?> sup = argC.getSuperclass();
if (sup != null)
invoker(cName,sup,param);
}
catch (Exception e) {
System.out.println(e);
}
}