Java getMethod with subclass parameter

一曲冷凌霜 提交于 2019-11-27 08:45:06

It's a bit longer than what you started with, but this does what you asked for... and a little more besides - for example, callMethod(receiver, "voidMethod") where voidMethod takes no arguments also works.

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:

If your testMethod function has parameter of FooSuperClass type:

 public void testMethod(FooSuperClass object){}

then, while you are trying to get a matching method with reflection: getClass().getMethod("testMethod", FooSubclass.class) will result in NoSuchMethodException. Because this getMethod(String name, Class<?>... parameterTypes function returns a Method object which is a public member method with the given name where parameterTypes parameter is an array of Class objects that identify the method's formal parameter types. There is actually no such method is declared with signature testMedthod(FooSubClass object) as the formal parameter type of the function is FooSuperClass. So, the correct invocation is:

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

or, passing the super class by calling SubClass.class.getSuperClass() as follows:

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

or, changing the method signature to: public void testMethod(FooSubClass object){} and then invoke as you are doing now:

receiver.getClass().getMethod("testMethod", FooSubclass.class)
                         .invoke(receiver, new FooSubclass());
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!