Подтвердить что ты не робот

Почему метод Java Area # equals не переопределяет Object # equals?

Я столкнулся с проблемой, вызванной Java java.awt.geom.Area#equals(Area). Проблема может быть упрощена до следующих unit test:

@org.junit.Test
public void testEquals() {
    java.awt.geom.Area a = new java.awt.geom.Area();
    java.awt.geom.Area b = new java.awt.geom.Area();
    assertTrue(a.equals(b)); // -> true

    java.lang.Object o = b;
    assertTrue(a.equals(o)); // -> false
}

После некоторой царапины и отладки головы я наконец увидел в источнике JDK, что подпись метода equals в Area выглядит следующим образом:

public boolean equals(Area other)

Обратите внимание, что это не @Override обычный equals метод из Object, а вместо этого просто перегружает метод более конкретным типом. Таким образом, два вызова в приведенном выше примере заканчиваются вызовом различных реализаций equals.

Поскольку это поведение присутствует с Java 1.2, я предполагаю, что это не считается ошибкой. Поэтому я больше заинтересован в том, чтобы выяснить, почему было принято решение не правильно переопределять метод equals, но в то же время обеспечить перегруженный вариант. (Еще один намек на то, что это было фактически принято, - отсутствие перезаписанного метода hashCode().)

Мое единственное предположение заключалось в том, что авторы опасались, что медленная реализация equals для областей непригодна для сравнения равенства при размещении Area в Set, Map и т.д. datastructures. (В приведенном выше примере вы могли бы добавить a в HashSet, и хотя b равен a, вызов contains(b) завершится с ошибкой.) И опять же, почему они не просто назвали сомнительный метод таким образом, чтобы он не сталкивался с таким фундаментальным понятием, как метод equals?

4b9b3361

Ответ 1

RealSkeptic, связанный с JDK-4391558 в комментарии выше. comment в этой ошибке объясняется аргументация:

Проблема с переопределением равно (Object) заключается в том, что вы также должны переопределить hashCode(), чтобы вернуть значение, которое гарантирует, что equals() true, только если хэш-коды двух объектов также равны.

а

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

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

deprecate equals (Area) и создать альтернативное имя для этого например, "areasEqual", чтобы избежать путаницы. К сожалению, старый метод останется и будет связан и поймал бы многих людей, которые намеревались вызвать равных (Объект) версия.

или

deprecate equals (Area) и изменить его реализацию точно равным (Object), чтобы избежать семантических проблем, если неправильные метод. Создайте новый метод с другим именем, чтобы избежать путаница для реализации старой функциональности, предоставляемой равными (Area).

или

реализовать equals (Object) для вызова equals (Area) и реализовать манекен hashCode(), который чтит контракт equals/hashCode в вырожденном путем возврата константы. Это сделает метод hashCode практически бесполезны и делают объекты Area почти бесполезными, поскольку ключи в HashMap или Hashtable.

или другие способы изменения поведения equals(Area), которые либо изменят его семантику, либо сделают ее несовместимой с hashCode.

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

Ответ 2

"Почему метод Java Area # equals не переопределяет Object # равно?"

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

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

Этот случай не заставляет нас переопределять, но он перегружен, поскольку он следует этим правилам:

1.) Число параметров для методов отличается.

2.) Типы параметров различны (например, изменение параметра, который был float для int).

"почему они не просто назвали сомнительный метод таким образом, чтобы он не сталкивался с таким фундаментальным понятием, как метод equals?"

Потому что это может привести людей в будущее. Если бы у нас была машина времени на 90, мы могли бы сделать это без этой проблемы.