Java getMethod with subclass parameter

倖福魔咒の 提交于 2019-11-26 14:19:23

问题


I'm writing a library that uses reflection to find and call methods dynamically. Given just an object, a method name, and a parameter list, I need to call the given method as though the method call were explicitly written in the code.

I've been using the following approach, which works in most cases:

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);
}

However, when one of the parameters is a subclass of one of the supported types for the method, the reflection API throws a NoSuchMethodException. For example, if the receiver's class has testMethod(Foo) defined, the following fails:

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

even though this works:

receiver.testMethod(new FooSubclass());

How do I resolve this? If the method call is hard-coded there's no issue - the compiler just uses the overloading algorithm to pick the best applicable method to use. It doesn't work with reflection, though, which is what I need.

Thanks in advance!


回答1:


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();
    }
  }
}




回答2:


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());


来源:https://stackoverflow.com/questions/19886065/java-getmethod-with-subclass-parameter

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