wrong number of arguments при вызове метода через рефлексию

201
26 января 2018, 22:35

Используя рефлексию вызываю методы, которые сортируют переданный массив a:

Set <Class <? extends Sort>> subTypesOf = (new Reflections("sorters")).getSubTypesOf(Sort.class);
for (Class <? extends Sort> c1 : subTypesOf) {
  Constructor <? extends Sort> emptyConstructor = c1.getConstructor();
  Sort objectToInvokeOn = emptyConstructor.newInstance();
  Method[] m1 = c1.getDeclaredMethods();
  for (Method method1: m1) {
    if (a != null) {
    System.out.println(c1.getName() + "." + method1.getName());
    method1.setAccessible(true);
    method1.invoke(objectToInvokeOn, new Object[] {a});

Ошибка на строке method1.invoke(objectToInvokeOn, new Object[]{a}); :

sorters.ExchangeSort.exchange
Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)...

Вот класс с методом exchange:

public class ExchangeSort extends Sort {
    public ExchangeSort() {
    }
    public void exchangeSort(int[] a) {
        exchange(a, 0, a.length - 1);
    }
      private int[] exchange(int[] a, int begin, int end) {
        int i = begin;
        int j = end;
        int average = (i - (i - j) / 2);
        if (i < j) {
            while ((i < average) && (a[i] <= a[average])) i++;
            while ((j > average) && (a[j] >= a[average])) j--;
            if (i > j) {
                swap(a, i, j);
            }
            if (i == average) {
                average = j;
            } else if (j == average) {
                average = i;
            }
            if (begin >= average) {
                return a;
            }
            return exchange(a, 0, average);
        }
        return exchange(a, average + 1, a.length - 1);
    }

Как решить проблему?

Мне нужно вызвать только методы, в которые передается массив int a[](все публичные), и getMethods() не подходит, т.к. есть public swap метод в наследнике Sort и тогда он тоже извлекается и пишет ту же ошибку.

Нашла, что можно добавить method1.setAccessible(true);, чтобы не извлекались приватные методы, но это не устранило ошибку.

Answer 1

Поиск метода по аргументам

Проблема в том, что в найденном классе вызываются все методы подряд, неважно предназначены они для сортировки или нет. Т.к. о вызываемом методе ничего не известно этот подход крайне ненадежен и небезопасен.

Можно получить список типов аргументов метода через Method.getParameterTypes и отсеять неподходящие.

Class<?>[] arguments = method1.getParameterTypes();
//если не один аргумент, пропускаем
if(arguments.length!=1) continue;
//если один, но не массив, тоже пропускаем
if(arguments[0]!=int[].class) continue;
System.out.println...

Либо использовать Class.getMethod, который ищет метод с заданными именем и типами аргументов. При таком подходе методы с другим списком аргументов вызваны не будут. Тем не менее, от ошибок вызова это не убережет, т.к. список аргументов мало о чем говорит:

public void exchangeSort(int[] a) {
     ...
public void killEveryone(int[] a) {

Человеческий подход: использовать Sort

К классу Sort есть обращения как в классе-сортировщике, так и в вызывающем классе. При этом класс никак не используется. Будет логично если в этом классе будет объявлен метод сортировки `void sort. В этом случае рефлексия будет использоваться для поиска классов-наследников и создания объектов, а сортировка будет выполняться вызовом метода.

Подробнее о подходе я писал в ответе на другой Ваш вопрос на такую же тему.

Альтернатива: аннотация

Для заполнения массива уже используется поиск аннотированного метода. Так же можно поступить и сортировкой. Создайте аннотацию Sorter и отмечайте ей методы сортировки

@Sorter
public void exchangeSort(int[] a) {
READ ALSO
Как сделать плейлист через Owl Carousel

Как сделать плейлист через Owl Carousel

1) Как сделать автовоспроизведение активного видео в Owl Carousel (чтобы при загрузке страницы чразу начиналось видео)?

314
Почему этот код работает медленно?

Почему этот код работает медленно?

Это мой первый скрипт, поэтому скорее всего тут куча идиотских решенийЕго задача: открыть спрятанное меню при клике, затемнить некоторые...

286