Лучшая практика для CompareTo (), когда аргумент должен быть набран из суперкласса - PullRequest
4 голосов
/ 17 августа 2011

Я ищу наилучшую практику для определения метода compareTo () в случае, когда класс реализует Comparable.Таким образом, сигнатура метода должна быть

public int compareTo(BaseClass arg)

. Сначала нужно проверить, является ли arg экземпляром этого класса, и если да, привести его к классу и сравнить его члены.Но если аргумент относится не к этому классу, а к какому-то другому классу, который также реализует BaseClass, что я возвращаю, чтобы он был рефлексивным?

Я знаю, что наилучшими практиками будет определение только CompareTo ()для класса это так, но эта вода над плотиной.

Ответы [ 3 ]

3 голосов
/ 17 августа 2011

Цитата из Effective Java, пункт 12:

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

Одним из следствий этих трех положений является то, что критерий равенства, введенный методом acompareTo, должен подчиняться тем же ограничениям, налагаемымпо равному контракту: рефлексивность, симметрия и транзитивность.Следовательно, применяется то же самое предостережение: нет способа расширить экземплярный класс новым компонентом значения при сохранении контракта CompareTo, если вы не хотите отказаться от преимуществ объектно-ориентированной абстракции (элемент 8). Тот же обходной путь применяется тоже.Если вы хотите добавить компонент значения в класс, который реализует Comparable, не расширяйте его;написать несвязанный класс, содержащий экземпляр первого класса.Затем предоставьте метод «view», который возвращает этот экземпляр.Это освобождает вас от реализации любого метода CompareTo, который вам нравится во втором классе, и позволяет его клиенту просматривать экземпляр второго класса как экземпляр первого класса, когда это необходимо.

Вы должныделайте то, что @BalusC рекомендовал в своем комментарии - используйте метод compareTo () базового класса для всех дочерних классов, ИЛИ сделайте обходной путь, предложенный выше, создав несвязанный класс, содержащий экземпляр первого класса.

2 голосов
/ 17 августа 2011

Ваша ошибка в вашем вопросе. Вам не нужно реализовывать public int compareTo(BaseClass arg). Вы должны реализовать 'public int compareTo (YourClass arg)'.

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

Но если вы все еще хотите использовать базовый класс в качестве аргумента, сделайте по крайней мере следующее:

public class Test {

}

class SubTest <T extends Test> implements Comparable<T> {
    @Override
    public int compareTo(T o) {
        // add your code with instanceof here
        return 0;
    }
}

По крайней мере, этот подход требует, чтобы аргумент был подклассом вашего базового класса.

1 голос
/ 17 августа 2011

В этом контексте рефлексивное означает obj.compareTo(obj) == 0. Что вы подразумеваете под рефлексивом здесь?

Что касается указанного контракта для CompareTo (T o), то необходимая семантика для вас - выбросить ClassCastException, если участвующие классы не могут быть осмысленно сопоставлены.

например. Учитывая

class Fruit {/* ..*/ }

class Apple extends Fruit {/* .. */ }

@Ignore("bad OO")
class GrannySmithApple extends Apple {/* .. */ }

class Orange extends Fruit {/* ... */ }

Можно утверждать, что

   Fruit a = new Apple();
   Fruit b = new GrannyApple();
   Fruit c = new Orange();

   // compare apples with apple?
   // makes sense to expect an int value
   r = a.compareTo(b)

   // compare apples with oranges?
   // makes sense to expect an exception
   boolean excepted = false;
   try {
       c.compareTo(a);
   } catch (ClassCastException e) { 
      excepted = true;
   } finally {
      assert excepted : "How can we compare apples with oranges?"
   }
...