Используя рефлексию вызываю методы, которые сортируют переданный массив 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);, чтобы не извлекались приватные методы, но это не устранило ошибку.
Поиск метода по аргументам
Проблема в том, что в найденном классе вызываются все методы подряд, неважно предназначены они для сортировки или нет. Т.к. о вызываемом методе ничего не известно этот подход крайне ненадежен и небезопасен.
Можно получить список типов аргументов метода через 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) {
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости