Как работать с varargs и reflection

Простой вопрос, как заставить этот код работать?

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(..) ищет только public методы. Из javadoc:

Возвращает объект Method, который отражает указанный метод открытого элемента classа или интерфейса, представленный этим объектом classа.

Обновление: после успешного получения метода вы можете вызвать его, используя:

 m.invoke(this, new Object[] {new String[] {"a", "s", "d"}}); 

то есть – создать новый массив Object с одним элементом – массивом String . С вашими именами переменных это будет выглядеть так:

 m.invoke(this, new Object[] {a}); 

// до редактирования:

Ваша проблема заключается в том, что getMethod ищет public участника.

Из Class.getMethod (основное внимание):

Возвращает объект Method который отражает указанный метод открытого участника classа или интерфейса, представленный этим объектом classа

Таким образом, у вас есть два варианта:

  • Сделать public void foo(String... s) и использовать getMethod
  • getDeclaredMethod этого используйте getDeclaredMethod

Обратите внимание, что такая же разница существует для getField/s vs getDeclaredField/s и getConstructor/s vs getDeclaredConstructor/s .


// invoke проблемы

Это особенно неприятно, но происходит то, что invoke(Object obj, Object... args) делает его сложным, если вам нужно передать массив ссылочного типа в качестве единственного аргумента, потому что он способен использовать Object[] , даже если он должен быть обернут внутри new Object[1] .

Ты можешь сделать:

 m.invoke(this, new Object[] {a}); // Bohzo's solution 

Это обходит механизм vararg. Более лаконично вы также можете сделать:

 m.invoke(this, (Object) a); 

Приведение к Object приводит к тому, что механизм vararg выполняет работу по созданию массива для вас.

Трюк также необходим при передаче null в качестве аргумента varargs и не имеет ничего общего с reflectionм.

 public void foo(String... ss) { System.out.println(ss[0]); } foo(null); // causes NullPointerException foo((String) null); // prints "null" 
  • Простой способ получить тип classа-оболочки в Java
  • Получить имя свойства как строку
  • GetEntryAssembly для веб-приложений
  • Прочитать значение атрибута метода
  • Изменить параметр атрибута во время выполнения
  • Получение размера поля в байтах с помощью C #
  • Как проверить, имеет ли объект определенный метод / свойство?
  • Является ли строка Java действительно неизменной?
  • Получение типа System.Type из частичного имени типа
  • Получить все classы в пути classа
  • Каков наилучший способ получить объект classа для типа массива?
  • Давайте будем гением компьютера.