2008-12-12 7 views
11

Beim Ausführen von FindBugs auf meinem Projekt, habe ich ein paar Instanzen des oben beschriebenen Fehlers.Findbugs Warnung: Equals-Methode sollte nichts über den Typ des Arguments annehmen

Nämlich überschreiben meine überschreibenden Versionen von equals das RHS-Objekt in den gleichen Typ wie das Objekt, in dem die überschreibende Version definiert ist.

Ich bin mir jedoch nicht sicher, ob ein besseres Design möglich ist, da AFAIK Java keine Varianz in den Methodenparametern zulässt. Daher ist es nicht möglich, einen anderen Typ für den Parameter equals zu definieren.

Mache ich etwas sehr falsch, oder sind FindBugs zu eifrig? Ein anderer Weg, diese Frage zu formulieren, ist: Was ist das richtige Verhalten, wenn das Objekt, das an equals übergeben wird, nicht der gleiche Typ wie ein LHS ist: Ist das ein false oder sollte es eine Ausnahme geben?

Zum Beispiel:

public boolean equals(Object rhs) 
{ 
    MyType rhsMyType = (MyType)rhs; // Should throw exception 
    if(this.field1().equals(rhsMyType.field1())... // Or whatever 
} 
+0

das klingt ein bisschen seltsam. Bitte zeigen Sie uns einen Code. –

Antwort

27

Typischerweise bei der Implementierung gleich können Sie überprüfen, ob die Klasse des Arguments gleich ist (oder kompatibel) an die implementierende Klasse, bevor sie gegossen wird. Etwas wie dieses:

if (getClass() != obj.getClass()) 
    return false; 
MyObj myObj = (MyObj) obj; 

Doing es dieses Weg verhindert die FindBugs Warnung.

Eine Randnotiz einen Kommentar zu adressieren:
Einige Leute argumentieren instanceof statt getClass zu verwenden Typsicherheit zu überprüfen. Es gibt eine große Debatte darüber, auf die ich nicht eingehen wollte, als ich feststellte, dass Sie die Klassengleichheit überprüfen können oder Kompatibilität, aber ich denke, ich kann nicht entkommen. Es läuft darauf hinaus - wenn Sie instanceof verwenden, können Sie die Gleichheit zwischen Instanzen einer Klasse und Instanzen ihrer Unterklasse unterstützen, aber Sie riskieren, den symmetrischen Vertrag von equals zu brechen. Generell würde ich empfehlen, nicht instanceof zu verwenden, außer Sie wissen, dass Sie es brauchen, und Sie wissen, was Sie tun. Für weitere Informationen siehe:

+4

Dies bedeutet im Wesentlichen Folgendes: Anstatt eine ClassCastException auszulösen, sollte Ihre equals() -Methode false zurückgeben. – Darron

+0

Aber ist das die richtige Praxis in diesen Situationen? Ich meine, im Idealfall hätte ich eine Kompilierzeit-Typprüfung gewünscht, die ich wegen Java-Einschränkungen nicht bekommen kann. – Uri

+0

Warum? Was ist los mit der Überprüfung auf Gleichheit zwischen nicht verwandten Typen? Es ist eine Frage mit einer vollkommen schönen und klaren Antwort. –

7

Sie sind wahrscheinlich so etwas wie dies zu tun:

public class Foo { 
    // some code 

    public void equals(Object o) { 
    Foo other = (Foo) o; 
    // the real equals code 
    } 
} 

In diesem Beispiel etwas über das Argument von equals() geht davon aus: Sie werden vorausgesetzt, es ist vom Typ Foo. Dies muss nicht der Fall sein! Sie können auch einen String bekommen (in diesem Fall sollten Sie fast unbedingt false zurückgeben).

So sollte der Code wie folgt aussehen:

public void equals(Object o) { 
    if (!(o instanceof Foo)) { 
    return false; 
    } 
    Foo other = (Foo) o; 
    // the real equals code 
} 

(oder verwenden Sie die strengeren getClass() != o.getClass() von Dave L. erwähnt

Sie auch es auf diese Weise aussehen könnte:

Integer i = new Integer(42); 
String s = "fourtytwo"; 
boolean b = i.equals(s); 

Gibt es einen Grund, dass dieser Code eine ClassCastException statt normal beenden und bwerfen sollte 10?

Ein ClassCastException als Antwort auf .equals() zu werfen wäre nicht sinnvoll. Denn auch wenn es eine dumme Frage ist ("Natürlich ist ein String niemals gleich einem Foo!"), Ist es immer noch ein gültiger mit einer ganz feinen Antwort ("no" == false).

0

Ich beginne meine equals (Object) Implementierungen wie folgt aus:

if ((object == null) || !(object instaceof ThisClass)) { 
    return false; 
} 

Dies wird auch die FindBugs Warnung verhindern, aber nicht automatisch false zurück, wenn eine Unterklasse von ThisClass in geben wird Es könnte auch in Betracht gezogen werden. gleich, besonders wenn die equals(Object) Methode nicht überschrieben wurde.

+3

Der Null-Check ist redundant mit instanceof. Seien Sie vorsichtig mit instanceof; Wenn der verfeinerte Vertrag eines Nicht-End-Gleichgestellten die Bedingungen für die Gleichheit nicht beschreibt (wie java.util.Set), werden Sie wahrscheinlich die Symmetrie-Anforderung aufheben. – erickson

1

Ich würde empfehlen, die Findbugs Warnung zu ignorieren. Wenn in der Praxis equals mit einem Objekt einer unerwarteten Klasse aufgerufen wird, handelt es sich mit ziemlicher Sicherheit um einen Fehler, und Sie möchten bei Fehlern schnell Fehler machen.

Zum Beispiel, wenn Sie eine 'ArrayList-Dateien' und Aufruf von files.contains ("MyFile.txt"), wäre es nett, wenn Sie eine ClassCastException haben. Stattdessen gibt Java einfach false zurück, und es dauert wahrscheinlich lange, bis Sie diesen Fehler entdecken.

Verwandte Themen