Простой вопрос, как делают эту работу кода?
public class T {
public static void main(String[] args) throws Exception {
new T().m();
}
public // as mentioned by Bozho
void foo(String... s) {
System.err.println(s[0]);
}
void m() throws Exception {
String[] a = new String[]{"hello", "kitty"};
System.err.println(a.getClass());
Method m = getClass().getMethod("foo", a.getClass());
m.invoke(this, (Object[]) a);
}
}
Вывод:
class [Ljava.lang.String;
Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
Test.class.getDeclaredMethod("foo", String[].class);
работает. Проблема в том, что getMethod (..)
выполняет поиск только общедоступных
методов. Из javadoc:
Возвращает объект Method, который отражает указанный общедоступный метод-член класса или интерфейса, представленного этим объектом Class.
Обновление: После успешного получения метода вы можете вызвать его, используя:
m.invoke(this, new Object[] {new String[] {"a", "s", "d"}});
то есть - создать новый массив Object
с одним элементом - массив String
. С вашими именами переменных это будет выглядеть так:
m.invoke(this, new Object[] {a});
// до редактирования:
Ваша проблема в том, что getMethod
ищет общедоступного члена
.
Из Class.getMethod
(выделено мной):
Возвращает объект
Method
, который отражает указанный общедоступный метод-член класса или интерфейса. представлен этим объектом класса
Итак, у вас есть два варианта:
public void foo (String ...s)
и используйте getMethod
getDeclaredMethod
вместо Обратите внимание, что такая же разница существует для getField / s
и getDeclaredField / s
и getConstructor / s
vs getDeclaredConstructor / s
.
// вызов
проблема
Это особенно неприятно, но случается так, что invoke (Object obj, Object ... args)
усложняет задачу, если вам нужно передать массив ссылочного типа в качестве единственного аргумента, поскольку он может быть приведен к Object []
, даже если вместо этого он должен быть заключен в новый объект [1]
.
Вы можете:
m.invoke(this, new Object[] {a}); // Bohzo's solution
Это обходит механизм vararg. Вы также можете сделать это более кратко:
m.invoke(this, (Object) a);
Приведение к Object
заставляет механизм vararg выполнять работу по созданию массива за вас.
Уловка также необходима при передаче null
в качестве аргумента переменной varargs и не имеет ничего общего с отражением.
public void foo(String... ss) {
System.out.println(ss[0]);
}
foo(null); // causes NullPointerException
foo((String) null); // prints "null"