2015-04-15 8 views
17

Ich bin relativ neu in Java und versuche nur, meinen Kopf zu verstehen @Override der equals() und hashcode() Methoden.
ich für die Methode equals kennen zu stimmen es sein muss:Welchen Teil des equals() Generalvertrags erfüllt mein equals() nicht

  1. Reflexive:a.equals(a)
  2. Symmetrisch:a.equals(b)dannb.equals(a)
  3. Transitive:a.equals(b) && b.equals(c)Danna.equals(c)
  4. Nicht null:! a.equals(null)

Ich kämpfe, welche der oben genannten Eigenschaften ich bin und bin nicht befriedigend zu lokalisieren, wenn meine overide des Verfahrens equals zu schreiben.

Ich bin mir bewusst, dass Eclipse diese für mich generieren kann, aber da ich das Konzept noch nicht vollständig verstanden habe, hilft es mir, es zu lernen.

Ich habe geschrieben, was ich denke, ist der richtige Weg, es zu tun, aber wenn ich mit der Eclipse-generierten Version überprüfe ich scheinen einige Aspekte "fehlen".

Beispiel:

public class People { 

    private Name first; //Invariants --> !Null, !=last 
    private Name last; // !Null, !=first 
    private int age; // !Null, ! <=0 
    ... 
} 

Was ich schrieb:

public boolean equals(Object obj){ 
    if (obj == null){ 
     return false; 
    } 
    if (!(obj instanceof People)){ 
     return false; 
    } 
    People other = (People) obj; 
    if (this.age != other.age){ 
     return false; 
    } 
    if (! this.first.equals(other.first)){ 
     return false; 
    } 
    if (! this.last.equals(other.last)){ 
     return false; 
    } 
    return true; 
} 

vs eclipse

public boolean equals(Object obj) { 
    if (this == obj) 
     return true; 
    if (obj == null) 
     return false; 
    if (getClass() != obj.getClass()) 
     return false; 

    People other = (People) obj; 
    if (first == null) { 
     if (other.first != null) 
      return false; 
    } else if (!first.equals(other.first)) 
     return false; 
    if (age != other.age) 
     return false; 
    if (last == null) { 
     if (other.last != null) 
      return false; 
    } else if (!last.equals(other.last)) 
     return false; 

    return true; 
} 

generiert mir fehlt:

  • if (this == obj) 
        return true; 
    
  • if (getClass() != obj.getClass()) 
        return false; 
    
  • Und für jede Variable:

    if (first == null) { 
        if (other.first != null) 
         return false; 
    } else if (!first.equals(other.first)) 
        return false; 
    

Ich bin mir nicht sicher, was getClass() und ist mein implmentation nicht richtig?

+0

Warum werfen Sie bei der Implementierung von equals für 'People' auf' Name'? Sieht aus wie ein Tippfehler. Bitte klären Sie. – Radiodef

+5

Sie könnten auch sehen [* "Irgendeinen Grund zu bevorzugen, getClass() über instanceof beim Generieren .equals()?" *] (Http://stackoverflow.com/q/596462/2891664) Eine ganze Antwort kann nur geschrieben werden dieses Thema allein. – Radiodef

+1

Sie haben immer noch wenn (!(obj instanceof Name)) {Zeile falsch –

Antwort

8

erste Stück Code:

if (this == obj) 
    return true; 

Dies verbessert die Leistung im Fall, dass Sie den Objektverweis gegen sich selbst zu vergleichen. Beispiel: a.equals(a);.

zweite Stück-Code:

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

Dieser vergleicht, wenn die Klasse der Referenz verglichen wird, ist die gleiche Klasse von this. Der Unterschied zwischen der Verwendung dieses Ansatzes und instanceof besteht darin, dass es restriktiver ist, wenn es mit einer Unterklasse verglichen wird. Beispiel:

public class Foo { } 
public class Bar extends Foo { } 

//... 
Foo foo = new Bar(); 
System.out.println(foo instanceof Bar); //prints true 
System.out.println(foo instanceof Foo); //prints true 
Foo foo2 = new Foo(); 
System.out.println(foo.getClass() == foo2.getClass()); //prints false 

Welches sollten Sie wählen? Es gibt keinen guten oder schlechten Ansatz, es hängt von Ihrem gewünschten Design ab.

Drittes Stück Code:

if (first == null) { 
     if (other.first != null) 
      return false; 
    } else if (!first.equals(other.first)) 
     return false; //For each variable. 

Das ist einfach eine Nullprüfung für jedes Objekt Referenzfeld in der Klasse. Wenn this.firstnull ist, wird this.first.equals(...) einen NullPointerException werfen.

+2

Wenn Sie sich fragen, warum das letzte Stück nicht 'Objects.equals' verwendet ... wurde dieser Teil von Eclipse wahrscheinlich geschrieben, bevor' Objects.equals' hinzugefügt wurde (in Java 7). – immibis

4

Ich glaube nicht, Ihre Implementierung ist falsch, aber ein paar Hinweise:

if (this == obj) 
     return true; 

ist eine Performance-Optimierung, es testet direkt als Referenz Gleichheit und Kurzschlüsse Tests, bei denen aista.

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

Ist ähnlich wie Ihre instanceof Anruf, optimiert eine NULL-Prüfung entfernt. Die anderen Aufrufe scheinen Null-Checks zu sein.

+4

Ähnlich, aber nicht dasselbe. 'instanceof' gilt für eine Unterklasse, die die" Symmetric "-Regel durchbrechen kann. – pkalinow

3

Sie brauchen nicht

if (obj == null){ 
     return false; 
} 
if (!(obj instanceof People)){ 
    return false; 
} 

zu schreiben, weil null immer false in instanceof Kontrollen gibt. So können diese Linien vereinfacht werden, um nur

if (!(obj instanceof People)){ 
    return false; 
} 

Was Ihre Hauptfrage, ob Ihre Methode die Anforderungen an ein equals() Verfahren erfüllt, genau genommen die Antwort nein ist, oder zumindest ist es potenziell zwielichtigen. Dies liegt daran, es möglich wäre, die Klasse zu erweitern, wie

folgt nun
public class SpecialPeople extends People { 

    // code omitted 

    @Override 
    public boolean equals(Object object) { 
     if (object == null || object.getClass() != getClass()) 
      return false; 
     SpecialPeople other = (SpecialPeople) object; 
     return other.getAge() == getAge() 
       && other.getFirst().equals(getFirst()) 
       && other.getLast().equals(getLast()); 
} 

annehmen a ist eine Instanz People und b ist eine Instanz SpecialPeople. Nehmen wir auch an, dass a und b denselben Namen und dasselbe Alter haben. Dann

a.equals(b) == true // instanceof check succeeds 
b.equals(a) == false // getClass() check fails 

Daher equals() ist nicht symmetrisch! Aus diesem Grund sollten Sie, wenn Sie instanceof statt getClass() in equals() verwenden, wahrscheinlich entweder die equals() Methode final oder die Klasse final.

+0

Wenn Sie obj.getClass verwenden, müssen Sie zuerst nach Null suchen. Das hängt von der Vorgehensweise ab, die du bei getClass oder instanceOf anwählst. –

+0

@ Noman_1 Zuerst habe ich nach "null" gesucht. –