Мне посоветовали не использовать отражение здесь ... Почему бы и нет? - PullRequest
5 голосов
/ 16 января 2012

Этот код используется для сортировки списка.Список может содержать тысячи элементов, но не более 10 тыс.

protected <E> int compareFields(E o1, E o2, String fieldName){
    try { 
        Comparable o1Data = (Comparable) o1.getClass().getMethod(fieldName).invoke(o1);
        Comparable o2Data = (Comparable) o2.getClass().getMethod(fieldName).invoke(o2);
        return o1Data == null ? o2Data == null ? 0 : 1 :
               o2Data == null ? -1 : o1Data.compareTo(o2Data);
    } catch(Exception e) {
        throw new RuntimeException(e);
    }
}

Мне посоветовали

«Пожалуйста, не используйте отражения для подобных вещей!предоставить метод с подходящим компаратором или метод для извлечения соответствующего свойства (может быть вычислено способом, не поддерживаемым исходным типом), или и тем, и другим. "

Пример лучшего способасделать это было бы неплохо.

Контекст: у меня есть много экранов с таблицами данных.Каждый из них построен из списка.Каждая таблица данных должна сортироваться по каждому из 6 столбцов.Столбцы имеют дату или строку.

Ответы [ 3 ]

5 голосов
/ 16 января 2012

Использование отражения здесь потенциально будет намного медленнее, так как вы добавляете количество кадров стека к каждому сравнению, используя getClass, getMethod и invoke вместо использования собственного метода сравнения объектов.

В идеале вы должны написать метод, чтобы избежать использования object в подписи. «Подходящий компаратор» будет, по крайней мере, сильно привязан к типу объектов (которые, как вы предполагаете, совпадают). Если вам необходимо динамическое сравнение полей (как оно выглядит), то, по крайней мере, отражение может быть заключено в этот компаратор.

Однако, если вы собираетесь вызывать это тысячи раз, было бы лучше предварительно связать Компаратор с полем, по которому вы сортируете. Таким образом, вы звоните getMethod только один раз, а не один раз для каждого отдельного сравнения.

1 голос
/ 16 января 2012

Другие ответы хорошо описывают, почему не рекомендуется использовать рефлексию.Я хочу добавить пример, используя более традиционное решение.

Вместо указания поля, которое используется для сравнения двух объектов, вы должны принять экземпляр Comparator в качестве аргумента.Таким образом, клиент, который использует этот метод, может указать, как сравнивать два объекта.

protected <E> int compareFields(E o1, E o2, Comparator<E> comparator) {
    return comparator.compare(o1, o2);
}

И пример вызова этой функции будет выглядеть так:

MyClass a = ...;
MyClass b = ...;
Comparator<MyClass> intFieldComparator = new Comparator<MyClass> {
    public int compare(MyClass o1, MyClass o2) {
        int field1 = o1.getIntField();
        int field2 = o2.getIntField();

        return field2 - field1;
    }
};

compareFields(a, b, intFieldComparator);

Вы можете определитьразличные компараторы, если вы хотите сравнить объекты, используя несколько полей.

1 голос
/ 16 января 2012

Трудно привести хороший пример без контекста, поэтому сейчас приведен небольшой список причин, по которым это не самая лучшая идея:

  1. В указанном поле нет гарантии того, что он сопоставим (не знаю, почемукод должен перехватить это исключение и переименовать его).
  2. Что если тип предоставленных объектов не должен сравниваться таким образом?(Это слишком общее имя метода, чтобы знать, как его использовать).
  3. Он не является строго типизированным.Предоставление имени поля в виде строки означает, что вам придется менять код везде, где меняется имя свойства, и будет сложно отследить, где вам нужно внести эти изменения.
  4. Отражение потенциально медленнеечем если бы он был реализован строго типизированным способом.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...