2016-10-12 10 views
1

Это написано во всех приличных курсах Java, что, если вы реализуете интерфейс Comparable, вы должны (в большинстве случаев) также переопределить метод equals, чтобы соответствовать его поведение.показывают, что равно идет рука об руку с CompareTo

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

+1

Возможный дубликат [java.lang.Comparable and equals] (http://stackoverflow.com/questions/6970879/java-lang-comparable-and-equals) –

ответ

4

Если вы не переопределите метод equals, он наследует его поведение от класса Object.
Этот метод возвращает true тогда и только тогда, когда указанный объект не является нулевым и относится к одному экземпляру.

Пусть следующий класс:

class VeryStupid implements Comparable 
{ 
    public int x; 

    @Override 
    public int compareTo(VeryStupid o) 
    { 
    if (o != null) 
     return (x - o.x); 
    else 
     return (1); 
    } 
} 

Мы создаем 2 экземпляра:

VeryStupid one = new VeryStupid(); 
VeryStupid two = new VeryStupid(); 
one.x = 3; 
two.x = 3; 

Вызов к one.compareTo(two) возвращает 0, обозначающие экземпляры равны, но вызов one.equals(two) возвращает ложь, указывающий, что они не равный.
Это непоследовательно.

0

метод int compareTo(T o) позволит вам знать, если T o есть (в некотором роде) выше или ниже по this, так что позволит вам заказать список T o. В сценарии int compareTo(T o) вы должны сделать:

  • есть о InstanceOfThis? => true/false;
  • is o EqualOfThis? => true/false;
  • o УлучшенныйОфис? => true/false;
  • is o InferiorOfThis? true/false;

Итак, вы видите, что у вас есть тест равенства, и лучший способ не реализовать равенство два раза - это поместить его в метод boolean equals(Object obj).

5

Я думаю, что вы можете победить их, показывая Comparable javadoc, который говорит:

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

Например, если добавить два ключа a и b такие, что (! A.equals (b) & & a.compareTo (b) == 0) в отсортированный набор, который не использует явный компаратор, вторая операция добавления возвращает false (и размер сортированный набор не увеличивается), поскольку a и b эквивалентны из отсортированные точки зрения.

Так особенно с SortedSet (и SortedMap), если метод compareTo возвращает 0, то считает, что она равна, как и не добавляет этот элемент второго раза, даже метод equals возвращает ложь, и вызывает путаницу, как указано в SortedSet javadoc

Обратите внимание, что порядок поддерживается отсортированный набор (предоставляется ли не явного сравнения) должны быть совместимы с равными, если отсортированный набор правильно реализовать интерфейс Set. (См. Интерфейс Comparable или интерфейс компаратора для точного определения , согласующегося с равными.) Это связано с тем, что интерфейс Set равен , определенному в терминах операции равенства, но отсортированный набор выполняет все сравнения элементов с помощью compareTo (или сравнить), поэтому два элемента, которые считаются равными этому методу, равны, с точки зрения . Поведение отсортированного набора равно , четкое, даже если его упорядочение не соответствует равным; это просто не подчиняется генеральному контракту интерфейса Set.

+0

Однажды забыл переопределить метод equals и отладить эта неустойчивая проблема была некрасивой. –

+0

Хорошие цитаты, однако, я думаю, что ваши комментарии относительно интерфейса SortedSet неверны. (Это наоборот), например. 'TreeSet' (который является' SortedSet') может содержать 2 объекта 'a' и' b', даже если 'a.equals (b) == true'. – bvdb

+0

@bvdb Я считаю, что все правильно. Интерфейс javadoc для Comparable говорит, что 'Например, если добавить два ключа a и b, чтобы (! A.equals (b) && a.compareTo (b) == 0) сортировать набор, который не использует явный компаратор, вторая операция добавления возвращает false (и размер сортированного набора не увеличивается), потому что a и b эквивалентны с точки зрения сортированного набора. ' –

0

Согласование compareTo и equals не требуется, но настоятельно рекомендуется.

Я дам ему выстрелило с этим примером:

private static class Foo implements Comparable<Foo> { 
    @Override 
    public boolean equals(Object _other) { 
     System.out.println("equals"); 
     return super.equals(_other); 
    } 
    @Override 
    public int compareTo(Foo _other) { 
     System.out.println("compareTo"); 
     return 0; 
    } 
} 
public static void main (String[] args) { 
    Foo a, b; 

    a = new Foo(); 
    b = new Foo(); 

    a.compareTo(b); // prints 'compareTo', returns 0 => equal 
    a.equals(b);  // just prints 'equals', returns false => not equal 
} 

Вы можете увидеть, что ваш (возможно, очень важный и сложный) код comparission игнорируются при использовании по умолчанию equals -метода в.

+1

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