Внедрение метода equals с использованием compareTo

Общий вопрос: при реализации переопределения метода по умолчанию equals в Java, что должно быть связано с простое использование уже реализованного метода compareTo против записи независимой логики в метод equals? Я заметил, что кто-то упомянул в другом вопросе, что foo.equals((String)null) возвращает false, тогда как String.compareTo((String)null) выбрасывает NullPointerException. Что делает эти несогласованные результаты идеальной функциональностью?

Пример equals:

@Override
public boolean equals(Object obj) {
    if (obj != null && obj instanceof MyClass) {
        MyClass msg = (MyClass)obj;
        return this.compareTo(msg) == 0;
    }
    return false;
}

Edit: Цитата из документации по Comparable

Естественное упорядочение для класса C называется согласованным с равен тогда и только тогда, когда e1.compareTo(e2) == 0 имеет такое же логическое значение как e1.equals(e2) для всех e1 и e2 класса C. Обратите внимание, что null не является экземпляр любого класса, а e.compareTo(null) должен NullPointerException, хотя e.equals(null) возвращает false

Edit:

После дальнейшего обзора я нахожу, что в документации Comparable также указано следующее:

Разработчик должен обеспечить sgn (x.compareTo(y)) == -sgn (y.compareTo(x)) для всех x и y. (Это означает, что x.compareTo(y) должен генерировать исключение iff y.compareTo(x) создает исключение.)

Ergo, так как null.compareTo(x) явно бросает NPE, x.compareTo(null) должен также бросать NPE. В то время как для равных, это не обязательно так. Я достаточно разбираюсь в правильном обращении с NPE, поэтому считаю это относительно значительным.

Ответы

Ответ 1

Разница между equals() и compareTo() заключается в том, что equals() просто проверяет, равны ли друг другу два объекта, где compareTo() используется для идентификации естественного порядка экземпляров указанного класса. Также метод equals() имеет контракт с методом hashCode(), но compareTo() не имеет.

Согласно JavaDoc:

Обратите внимание, что null не является экземпляром какого-либо класса, а e.compareTo(null) должен вызывать исключение NullPointerException, даже если e.equals(null) возвращает ложь.

Настоятельно рекомендуется, но строго не требуется, чтобы (x.compareTo(y) == 0) == (x.equals(y)). Вообще говоря, любой класс который реализует интерфейс Comparable и нарушает это условие должен четко указывать этот факт. Рекомендуемый язык: "Примечание: этот класс имеет естественное упорядочение, которое несовместимо с равными".

Вы можете свободно использовать логику метода compareTo() в своем методе equals(), но имейте в виду все контракты на equals(), hashCode() и контракт от метода JavaDoc для compareTo(). Если они не конфликтуют друг с другом, продолжайте.

Я думаю, что заключение контрактов является более важным.

Ответ 2

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

Помимо этого, следуя DRY, было бы неплохо повторить использование кода, как вы предложили.