Подтвердить что ты не робот

Отражение Java: getMethod (метод String, Object []. Class) не работает

У меня есть следующий код:

public void myMethod(Object... args) {
    System.out.println("this is myMethod");
}

public void invokeMyMethod() {
    Method s = this.getClass().getMethod("myMethod", Object[].class);
    Object[] ex = new Object[2];
    ex[0] = "hi";
    ex[1] = "there";
    s.invoke(this, ex);
}

Я получаю исключение java.lang.IllegalArgumentException: неправильное количество аргументов. Что не так?

4b9b3361

Ответ 1

Вам нужно вызвать метод следующим образом:

s.invoke(this, new Object[]{new Object[]{"hi", "there"}});

(... или используйте альтернативу в ответе @Jon.)

Причина, по которой ваш текущий код выходит из строя, заключается в том, что методы Java-кода реализуются на Java. По существу, T1 xxx(T2... args) является синтаксическим сахаром для T1 xxx(T2[] args). И когда вы вызываете методы, xxx(arg1, arg2, arg3) является синтаксическим сахаром для xxx(new T2[]{arg1, arg2, arg3}).

В этом случае вы пытаетесь вызвать varadic-метод, используя другой метод varadic с тем же самым базовым типом массива, и существует множество возможных интерпретаций кода.

Когда есть две возможные интерпретации варадического вызова, Java предполагает, что вы пытаетесь использовать "unsugared" версию вызова вместо "sugared". Или, точнее, "сахаристая" интерпретация используется тогда и только тогда, когда:

  • количество фактических аргументов не равно количеству формальных параметров или
  • последний фактический аргумент НЕ присваивается совместимым с типом (массив) последнего формального параметра.

Если вам интересно, это поведение указано в JLS в разделе 15.12.4.2.

Итак... мое решение работает, заставляя неварадическую интерпретацию и явно конструируя требуемый массив. Решение @Jon работает, заставляя правильную интерпретацию varadic.

Ответ 2

Проблема здесь в том, что переменные аргументы (Object...), которые Method.invoke принимает.

Изменение этой строки

 s.invoke(this, ex);

к этому

 s.invoke(this, (Object)ex);

будет работать.

В фоновом режиме Object... передается как Object[]. Java видит ваш Object[] и не ставит его в другой Object[]. Отбрасывая на Object, теперь он просто видит это и возвращается к своему нормальному поведению - так же, как и другие ответы, выполняемые вручную.

Ответ 3

Вы можете использовать dp4j для ответа на ваш вопрос:

    $ javac -cp ../dp4j-1.2-SNAPSHOT-jar-with-dependencies.jar -All -Averbose=true MyClass.java
MyClass.java:7: Note: 
public class MyClass {

public MyClass() {
    super();
}

public void myMethod(Object... args) {
    System.out.println("this is myMethod");
}

@com.dp4j.Reflect()
public void invokeMyMethod() throws java.lang.ClassNotFoundException, java.lang.NoSuchFieldException, java.lang.IllegalAccessException, java.lang.NoSuchMethodException, java.lang.reflect.InvocationTargetException, java.lang.IllegalArgumentException {
    final java.lang.reflect.Method myMethodWithArrayMethod = Class.forName("MyClass").getDeclaredMethod("myMethod", .java.lang.Object[].class);
    myMethodWithArrayMethod.setAccessible(true);
    myMethodWithArrayMethod.invoke(this, new .java.lang.Object[1][]{new .java.lang.Object[2][]{"hi", "there"}});
}

public static void main(String... args) throws Exception {
    new MyClass().invokeMyMethod();
}
}
public void invokeMyMethod() {
            ^

$ java MyClass
this is myMethod