Внедрение метода 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, было бы неплохо повторить использование кода, как вы предложили.