2015-02-17 8 views
22

Ich stieß gerade auf ein Problem, das durch Javas java.awt.geom.Area#equals(Area) Methode verursacht wurde. Das Problem kann auf die folgende Einheit Test vereinfacht werden:Warum ist Java's Area # gleich Methode nicht überschreiben Objekt # ist gleich?

@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 
} 

Nachdem einige am Kopf kratzen und Debugging, ich schließlich in der JDK Quelle sah, dass die Unterzeichnung des equals Methode in Area wie folgt aussieht:

public boolean equals(Area other) 

Beachten sie, dass es funktioniert nicht@Override die normale equals Methode von Object, sondern Überlastungen nur die Methode mit einer konkreteren Art. Daher rufen die beiden Aufrufe im obigen Beispiel verschiedene Implementierungen von equals auf.

Da dieses Verhalten seit Java 1.2 vorliegt, nehme ich an, dass es sich nicht um einen Fehler handelt. Ich bin daher mehr daran interessiert herauszufinden, warum die Entscheidung wurde nicht richtig übersteuern die equals Methode, aber gleichzeitig eine überlastete Variante. (Ein weiterer Hinweis, dass dies eine tatsächliche Entscheidung ist das Fehlen einer überschrieben hashCode() Methode.)

Meine einzige Vermutung wäre, dass die Autoren befürchten, dass die langsame equals Umsetzung für Bereiche ist nicht geeignet für den Vergleich Gleichheit bei der Platzierung Area s in Set, Map, etc. Datenstrukturen. (Im obigen Beispiel könnten Sie zu einer HashSet hinzufügen, und obwohl b gleich a ist, wird das Aufrufen von contains(b) fehlschlagen.) Warum haben sie dann nicht einfach die fragwürdige Methode auf eine Weise benannt, die nicht mit einer solchen kollidiert grundlegendes Konzept wie die equals Methode?

+1

Beachten Sie, dass 'hashCode' ebenfalls nicht überschrieben wird.Ich denke, was sie hier tun, ist nur eine "Vergleich" -Methode, die zufälligerweise den gleichen Namen wie "Object.equals()" hat. Persönlich hätte ich ihm einen anderen Namen gegeben, um Verwirrung zu vermeiden. – RealSkeptic

+0

Die Java-API folgt nicht immer den Best Practices, und das sieht nach einem Versehen aus. Versuchen Sie, diese Frage in den Oracle-Entwickler-E-Mail-Listen zu stellen und sehen Sie, was das offizielle Wort ist. Wenn es ein Versehen ist, war Sun/Oracle immer sehr zurückhaltend, API-Änderungen nach der Veröffentlichung vorzunehmen. Was könnte bedeuten, dass es als ein Versehen begann, das es in eine Freigabe machte, und jetzt gerade in der Zeit eingefroren ist. –

+7

Siehe [Bug 4391558] (https://bugs.openjdk.java.net/browse/JDK-4391558) – RealSkeptic

Antwort

4

RealSkeptic mit JDK-4391558 in einem Kommentar oben verbunden. Die comment in dem Fehler erklärt die Gründe:

Das Problem mit überwiegendem equals (Object) ist, dass müssen Sie auch überschreibt hashCode() einen Wert zurückgeben, die garantiert, dass equals() ist nur wahr, wenn die Hashcodes der beiden Objekte sind auch gleich.

aber:

Das Problem hierbei ist, dass Area.equals (Area) führt keine sehr Straight-Forward-Vergleich. Es wird sorgfältig jedes einzelne Stück Geometrie in den beiden Bereichen und Tests überprüft, um zu sehen, ob sie die gleichen geschlossenen Räume abdecken. Zwei Gebietsobjekte könnten eine vollständige unterschiedliche Beschreibung des gleichen umschlossenen Raumes haben und gleich (Bereich) würde feststellen, dass sie gleich waren.

Also im Grunde sind wir mit einer Reihe von links nicht so angenehm Optionen, wie zum Beispiel:

deprecate equals (Area) und erstellen Sie einen alternativen Namen für diesen Betrieb, wie zum Beispiel " AreasEqual ", um die Verwirrung zu vermeiden. Leider würde die alte Methode bleiben und wäre verknüpfbar und würde viele Leute, die die gleiche (Object) Version aufrufen möchten, fangen.

oder:

deprecate gleich (Area) und deren Umsetzung ändern zu sein, genau dass der equals (Object), um semantische Probleme, wenn die falsche Methode aufgerufen wird, zu vermeiden. Erstellen Sie eine neue Methode mit einem anderen Namen, um Verwirrung zu vermeiden, um die alte Funktionalität von Equals (Area) zu implementieren.

oder:

implementieren equals (Object) gleich zu nennen (Area) und implementieren eine Dummy- hashCode(), die die Gleichen/hashCode Vertrag in einer degenerierten Weise ehrt, indem eine Konstante zurück. Dies würde die hashCode-Methode im Wesentlichen nutzlos machen und Area-Objekte als Schlüssel in einer HashMap oder Hashtable fast nutzlos machen.

oder andere Möglichkeiten, um die equals(Area) Verhalten zu ändern, die entweder würde seine Semantik ändern oder es mit hashCode inkonsistent machen.

Die Änderung scheint von den Betreuern weder machbar (weil keine der beiden im Fehlerkommentar beschriebenen Optionen das Problem löst), noch wichtig (da die Methode, wie implementiert, ziemlich langsam ist und wahrscheinlich nur immer true zurück, wenn eine Instanz von Area mit sich selbst verglichen wird, wie der Kommentator sagt).

0

"Warum ist Java's Area # equals Methode nicht überschreiben Objekt # equals?"

Da das Überschreiben für überladene Methoden, bei denen die Parameter unterschiedliche Typen sind, nicht erforderlich ist.

Eine überschriebene Methode hätte genau den gleichen Methodennamen, Rückgabetyp, Anzahl der Parameter und Typen der Parameter wie die Methode in der Elternklasse, und der einzige Unterschied wäre die Definition der Methode.

Dieser Fall hat uns zwingen, nicht außer Kraft zu setzen, aber es ist eine Überlastung, wie sie diese Regeln folgt:

1.) Die Anzahl der Parameter für die Methoden unterschiedlich ist.

2.) Die Parametertypen sind unterschiedlich (wie das Ändern eines Parameters, der ein float war, zu einem int).

"Warum haben sie nicht einfach die fragwürdige Methode so benannt, dass sie nicht mit einem so grundlegenden Konzept kollidiert wie die equals-Methode?"

Weil dies Menschen in die Zukunft gehen könnte. Wenn wir eine Zeitmaschine bis in die 90er hätten, könnten wir es ohne diese Sorge machen.

+1

Sie haben seine Frage missverstanden. Die Frage ist, warum Sie es überladen und nicht überschreiben. Der mit @RealSkeptic verknüpfte Fehler liefert einige Einblicke. –

+0

@DeepakBala Ich habe angegeben, warum Sie es nicht überschreiben und wie das Konzept den Regeln der Überladung folgt. Nicht sicher, was du meinst, als es scheint, dass ich die Frage beantwortet habe, kannst du klären? – BAR

+0

Entschuldigung, aber wie ich in meiner Frage gesagt habe, bin ich mir durchaus bewusst, was Übersteuern und Überladen ist und wann jeder genutzt werden kann oder nicht. Aber wie @DeepakBala darauf hingewiesen hat, fehlt mir dabei meine Frage komplett. Ich kann den Status quo gut sehen (und verstehen), wollte aber wissen, warum diese scheinbar problematische Entscheidung überhaupt erst gemacht wurde. – Frank

Verwandte Themen