Как работать с varargs и отражением

Простой вопрос, как делают эту работу кода?

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)
24
задан PeterMmm 8 April 2010 в 14:55
поделиться

2 ответа

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});
47
ответ дан 28 November 2019 в 22:53
поделиться

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

Ваша проблема в том, что 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"
10
ответ дан 28 November 2019 в 22:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: