Getting getDeclaredMethods() to match a varargs me

2020-03-06 07:12发布

问题:

I want to use getDeclaredMethod() to find a method with this signature:

public void foo(String inArg1, Object... inArgs);

Using this call:

Class<?>[] argClasses = { String.class, Integer.class };
Method m = clazz.getDeclaredMethod("foo", argClasses);

But it generates a NoSuchMethodException exception. However, it is possible to invoke the method (assuming you find it some other way):

Object[] args = { "arg1", new Integer(2) };
m.invoke(instance, args);

I could list them all, with getDeclaredMethods(), and then try to do the signature matching myself, but that seems like a lot of work.

Should what I want to do be possible? Am I just missing something dumb?

回答1:

The method is callable with any object(s) because it is declared to accept object(s). - But, because it is declared with Object type you won't find via getDeclaredMethod() if you don't search for the exact declared type.

You should be able, though, to iterate over all declared methods and check on their parameter types to see if they are assignable from your given type to find all methods which are callable with your parameters.

Example:

Class[] signature = {String.class, Integer.class};
Method[] methods = someClass.getDeclaredMethods();

for ( Method m : methods ) {
  Class[] params = m.getParameterTypes();
  if ( params.length == signature.length ) {
    int i;
    for ( i = 0; i < signature.length && params[i].isAssignableFrom( signature[i] ); i++ ) {

    }
    if ( i == signature.length ) {
      System.out.println("Found matching method: " + m.getName());
    }
  }
}

However, I have not checked which type(s) Object... actually is assignable from. I assume that it is not Integer but rather Integer[] since the varargs are compiled to arrays.



回答2:

A vararg argument is just syntactic sugar for an array. The signature of the method is

foo(String, Object[]);

and not

foo(String, Integer);


回答3:

The only legal way to find foo method is

Class<?>[] argClasses = { String.class, Object[].class };
Method m = clazz.getDeclaredMethod("foo", argClasses);

as for

Object[] args = { "arg1", new Integer(2) };
m.invoke(instance, args);

it's quite legal, just as calling foo without reflection

foo("str", new Integer(2));


回答4:

You should treat varargs as an array:

Class<?>[] argClasses = { String.class, Object[].class };
Method m = clazz.getDeclaredMethod("foo", argClasses);