带有子类参数的Java getMethod

我正在编写一个使用reflection来动态查找和调用方法的库。 只给出一个对象,一个方法名和一个参数列表,我需要调用给定的方法,就好像方法调用是在代码中显式编写的一样。

我一直在使用以下方法,在大多数情况下都可以使用:

static void callMethod(Object receiver, String methodName, Object[] params) { Class[] paramTypes = new Class[params.length]; for (int i = 0; i < param.length; i++) { paramTypes[i] = params[i].getClass(); } receiver.getClass().getMethod(methodName, paramTypes).invoke(receiver, params); } 

但是,当其中一个参数是方法支持的类型之一的子类时,reflectionAPI会NoSuchMethodException 。 例如,如果接收者的类定义了testMethod(Foo) ,则以下操作失败:

 receiver.getClass().getMethod("testMethod", FooSubclass.class).invoke(receiver, new FooSubclass()); 

即使这有效:

 receiver.testMethod(new FooSubclass()); 

我该如何解决这个问题? 如果方法调用是硬编码的,则没有问题 – 编译器只使用重载算法来选择最适用的方法。 但它不适用于reflection,这是我需要的。

提前致谢!

它比你开始时要长一点,但是这样做你要求的……还有一点 – 例如,callMethod(接收器,“voidMethod”),其中voidMethod不带参数也有效。

 static void callMethod(Object receiver, String methodName, Object... params) { if (receiver == null || methodName == null) { return; } Class cls = receiver.getClass(); Method[] methods = cls.getMethods(); Method toInvoke = null; methodLoop: for (Method method : methods) { if (!methodName.equals(method.getName())) { continue; } Class[] paramTypes = method.getParameterTypes(); if (params == null && paramTypes == null) { toInvoke = method; break; } else if (params == null || paramTypes == null || paramTypes.length != params.length) { continue; } for (int i = 0; i < params.length; ++i) { if (!paramTypes[i].isAssignableFrom(params[i].getClass())) { continue methodLoop; } } toInvoke = method; } if (toInvoke != null) { try { toInvoke.invoke(receiver, params); } catch (Exception t) { t.printStackTrace(); } } } 

 receiver.testMethod(new FooSubclass()); even though this works: 

如果你的testMethod函数有FooSuperClass类型的参数:

  public void testMethod(FooSuperClass object){} 

然后,当您尝试使用reflection获取匹配方法时: getClass().getMethod("testMethod", FooSubclass.class)将导致NoSuchMethodException 。 因为这个getMethod(String name, Class... parameterTypes函数返回一个Method对象,它是一个具有给定name的公共成员方法,其中parameterTypes参数是一个Class对象数组,用于标识方法的forms参数类型 。实际上没有使用签名testMedthod(FooSubClass object)声明这样的方法,因为函数的forms参数类型是FooSuperClass 。因此,正确的调用是:

 receiver.getClass().getMethod("testMethod", FooSuperClass.class) .invoke(receiver, new FooSubclass()); 

或者 ,通过调用SubClass.class.getSuperClass()传递超类,如下所示:

 receiver.getClass().getMethod("testMethod", FooSubClass.class.getSuperclass()) .invoke(receiver, new FooSubclass()); 

或者 ,将方法签名更改为: public void testMethod(FooSubClass object){}然后像现在一样调用:

 receiver.getClass().getMethod("testMethod", FooSubclass.class) .invoke(receiver, new FooSubclass());