Отражение 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: неправильное количество аргументов. Что не так?
Ответы
Ответ 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