Как получить объект класса с помощью рефлексии (для вызова нестатичного метода)?

230
11 января 2018, 22:05

Код:

public static void runAllAnnotatedMethods() throws Exception {
    Class<?> c = Class.forName("fillers.ArrayFiller");
    Method[] m = c.getDeclaredMethods();
    for (Method method : m) {
        long start = System.nanoTime();
        if (method.isAnnotationPresent(Filler.class)) {
            // массив `int[] a` создается рандомно в статическом методе и находиться по аннотации @Filler
            int[] a = (int[]) method.invoke(null);
            //в пакете sorters ищу все классы, унаследованы от Sort(там разные методы сортировки массива)
            Set<Class<? extends Sort>> subTypesOf = (new Reflections("sorters")).getSubTypesOf(Sort.class);
            //предполагаемое объявление объекта(скорее не правильное)
            Object objectToInvokeOn= subTypesOf;
            for (Class c1 : subTypesOf) {
                Method[] m1 = c1.getDeclaredMethods();
                for (Method method1 : m1) {
                if (a != null) {
                    //попытка вызвать не статический метод, параметр которого тот массив а 
                    method1.invoke(objectToInvokeOn, a);
                    long count = System.nanoTime() - start;
                    System.out.println(count);
                }

Хотела разобраться сама, но не получается. Не могу понять откуда брать object для invoke. Ошибка в строке method1.invoke(objectToInvokeOn, a);

Вот пример класса, метод которого надо вызвать(все эти классы наследуются от Sort):

public class ArraySort extends Sort {
    public void arraySort(int[] a){
        Arrays.sort(a);
    }
}
Answer 1

Без рефлексии метод вызывается так:

//получаем массив
int[] a 
//вызываем конструктор для создания объекта
ArraySort objectToInvokeOn = new ArraySort();
//вызываем метод с переданными значениями
objectToInvokeOn.arraySort(a);

Соответственно, чтобы получить objectToInvokeOn нужно вызвать конструктор класса ArraySort.

Чтобы сделать это через рефлексию нужно сделать следующее (по шагам):

  1. Получить класс

    subTypesOf представляет из себя не один, а множество классов (Set<Class<? extends Sort>>. В коде уже есть цикл, который перебирает классы по одному, в нем и нужно создавать объекты:

    for(Class<? extends Sort> c1 : set) {

    Чтобы не терять информацию о типе заменил Class на Class<? extends Sort>.

  2. Получить конструктор

    У класса ArraySort есть конструктор по-умолчанию (публичный, без аргументов). Его можно получить с помощью метода Class.getConstructor:

    Constructor<? extends Sort> emptyConstructor = c1.getConstructor();

    Если у какого-либо из найденных классов не будет такого конструктора, то нужно будет понять как должны создаваться объекты класса и вызвать соответствующие методы/конструкторы.

  3. Вызвать конструктор

    Конструктор вызывается методом Constructor.newInstance:

    Sort objectToInvokeOn = emptyConstructor.newInstance();

    Опять-таки, здесь используется конструктор без аргументов. Для вызова конструктора с аргументами их нужно передать в newInstance.

После всех этих манипуляций для каждого класса получен объект типа Sort от которого можно выполнять нестатичные методы.

Улучшение: использование Sort.

Сейчас Sort используется только для поиска классов. При этом у найденных классов вызываются все объявленные методы, что может быть неудобно если у классов будут другие функции кроме сортировки.

Вместо этого можно воспользоваться тем что через рефлексию уже получен объект класса Sort от которого можно вызывать методы Sort напрямую.

Для этого нужно объявить метод сортировки непосредственно в Sort. При этом сделать класс и метод абстрактными, чтобы наследники в обязательном порядке реализовали свою сортировку:

abstract class Sort {
    abstract void arraySort(int[] a);
}

если в Sort нет других методов/полей, то можно преобразовать Sort в интерфейс.

После этого можно не перебирать методы через рефлексию, а сразу вызвать нужный от объекта-сортировщика:

objectToInvokeOn.sortArray(a);

P.S. если стоит задача проверять сортировщики, то нужно будет копировать изначальное состояние массива a, иначе все сортировщики кроме первого будут получать уже отсортированный массив.

READ ALSO
TreeMap отсортированный по ключу

TreeMap отсортированный по ключу

Задача такая: Необходим мониторинг количества ip адресов с которых приходит наибольшее количество пакетов и выводить на экран топ 10 адресов...

225
JavaFX Layout в родительском элементе

JavaFX Layout в родительском элементе

Доброго времени суток! Столкнулся со следующей проблемой: Пишу игру на JavaFXРеализую движение персонажа

332
Java 8 stream groupingBy

Java 8 stream groupingBy

Подскажите как преобразовать:

276
Сокеты. Прием и отдача данных. Андроид

Сокеты. Прием и отдача данных. Андроид

Есть клиент(андроид прил) и Сервер(Ява прога)

224