Java reflection: automatically invoke the right ov

2019-07-13 18:19发布

问题:

Say have an overloaded method called doTask:

public class Game {
  void doTask(Joker joker);
  void doTask(Batman batman, Robin robin);
}

I would like to invoke the right method, given the name of the method ("doTask") and an array of parameters whose number and types are not known a priori.

Normally, this involves three steps at least:
1. Find the number of the parameters and their types, and make an array Class[] myTypes.
2. Identify the correct overloaded Method, i.e. Method rightMethod = game.getClass().getMethod("doTask", myTypes);
3. Invoke the method: rightMethod.invoke(paramArray).

Does there exist a facility to ask Java reflection to automatically identify the right overloaded method to use, and save us from having to do Steps 1 and 2? I'm thinking ideally, this would be like:
Library.invoke("doTask", paramArray);

回答1:

There is such a facility, java.beans.Statement, resp. Expression if a return value is needed:

Game game = new Game();
Joker joker = new Joker();
Statement st = new Statement(game, "doTask", new Object[]{ joker });
st.execute();

However, it only works for public methods.

Also, unlike java.lang.reflect.Method, this facility has not been adapted to support varargs parameters, so you have to create a parameter array manually.

It can be demonstrated, that it does the work of selecting the right target method based on the argument types, which are not necessarily identical to the parameter types:

ExecutorService es = Executors.newSingleThreadExecutor();
class Foo implements Callable<String> {
    public String call() throws Exception {
        return "success";
    }
}
// has to choose between submit(Callable) and submit(Runnable)
// given a Foo instance
Expression ex = new Expression(es, "submit", new Object[]{ new Foo() });
Future<?> f = (Future<?>)ex.getValue();
System.out.println(f.get());
es.shutdown();


回答2:

First - to answer your question - no, there is no such facility.

Second, step 2 is a bit more complicated as it doesn't suffice to create a class array from the parameters and call getMethod.

Actually you have to iterate over all methods, that match the name, number of arguments and compare the argument types of the method for assignment compatibility for the given argument types (i.e. methodArgType.isAssignableFrom(paramType)), to ensure that compatible subtypes of the method arguments types are correctly reflected. Things get slightly more complicated with varargs.