Überschreiben der java-equals () - Methode nicht funktioniert?
-
06-07-2019 - |
Frage
Ich lief in eine interessante (und sehr frustrierende) Problem mit der equals()
Methode heute verursacht, was ich dachte, eine gut getestete Klasse zum Absturz zu bringen und verursachen einen Fehler, der brauchte eine sehr lange Zeit auf die Spur.
Nur der Vollständigkeit halber, ich war nicht mit einem IDE-oder debugger - just good old fashioned text-editor und System.aus ist.Die Zeit war sehr begrenzt, und es war ein Schulprojekt.
Wie auch immer -
Ich war die Entwicklung eines basic Einkaufswagen, die könnte enthalten ein ArrayList
von Book
Objekte.Um die Durchführung der addBook()
, removeBook()
, und hasBook()
Methoden der Wagen, ich wollte überprüfen, ob die Book
bereits in der Cart
.Also gehe ich aus -
public boolean equals(Book b) {
... // More code here - null checks
if (b.getID() == this.getID()) return true;
else return false;
}
Alles funktioniert gut, im Test.I create 6 Objekte und füllen Sie diese mit Daten.Viele Hinzugefügt, entfernt hat () - Operationen auf Cart
und alles funktioniert gut.Ich habe gelesen, dass Sie können entweder haben equals(TYPE var)
oder equals(Object o) { (CAST) var }
aber angenommen, dass, da es arbeitete, spielte es keine Rolle, zu viel.
Dann lief ich in ein problem - ich benötigt wird, um eine Book
Objekt mit nur die ID
in es aus der Book-Klasse.Keine weiteren Daten in Sie eingegeben.Grundsätzlich sind die folgenden:
public boolean hasBook(int i) {
Book b = new Book(i);
return hasBook(b);
}
public boolean hasBook(Book b) {
// .. more code here
return this.books.contains(b);
}
Alle von einer plötzlichen, die equals(Book b)
Methode nicht mehr funktioniert.Dies dauerte eine SEHR lange Zeit auf die Spur, ohne einen guten debugger und vorausgesetzt, die Cart
Klasse wurde ordnungsgemäß getestet und korrigieren.Nach swaapping der equals()
Methode, die der folgenden:
public boolean equals(Object o) {
Book b = (Book) o;
... // The rest goes here
}
Alles begann wieder zu arbeiten.Gibt es einen Grund, die Methode, die beschlossen, nicht zu nehmen das Buch-parameter, obwohl es eindeutig war ein Book
Objekt?Der einzige Unterschied schien zu sein, es instanziiert wurde in der gleichen Klasse, und nur gefüllt mit einer Daten-Mitglied.Ich bin sehr, sehr verwirrt.Bitte, etwas Licht?
Lösung
In Java, die equals()
Methode geerbt von Object
ist:
public boolean equals(Object other);
In anderen Worten, der parameter muss vom Typ Object
.
Die ArrayList
verwendet der richtigen equals-Methode, wo Sie waren, ruft immer die, die nicht richtig überschreiben Object
's gleich.
Nicht zu überschreiben die Methode richtig Probleme verursachen können.
Ich überschreiben entspricht den folgenden everytime:
@Override
public boolean equals(Object other){
if (other == null) return false;
if (other == this) return true;
if (!(other instanceof MyClass))return false;
MyClass otherMyClass = (MyClass)other;
...test other properties here...
}
Die Verwendung des @Override
annotation kann helfen, eine Tonne mit dummen Fehlern.
Verwenden Sie es, Wann immer Sie denken, dass Sie ein überwiegendes super-Klasse " oder interface-Methode.So, wenn Sie es falsch machen, erhalten Sie einen Kompilierungsfehler.
Andere Tipps
Wenn Sie Eclipse nur nach oben Menü gehen Sie mit
Quelle -> Gene equals () und hashCode ()
Ein wenig vom Thema auf Ihre Frage, aber es ist wahrscheinlich erwähnenswert, trotzdem:
Commons Lang hat einige ausgezeichnete Methoden bekam man in zwingende equals und hashcode verwenden können. Check out EqualsBuilder.reflectionEquals (...) und HashCodeBuilder.reflectionHashCode (... ). Ersparte mir viele Kopfschmerzen in der Vergangenheit -. Obwohl natürlich, wenn Sie gerade tun wollen „gleich“ auf ID nicht Ihre persönlichen Umstände passen
Ich bin damit einverstanden, dass Sie die @Override
Anmerkung verwenden sollen, wenn Sie überschreiben equals (oder eine andere Methode).
Eine weitere schnelle Lösung, die vorformulierten Code speichert Lombok EqualsAndHashCode Anmerkung . Es ist einfach, elegant und anpassbar. Und ist, hängt nicht von der IDE . Zum Beispiel:
import lombok.EqualsAndHashCode;
@EqualsAndHashCode(of={"errorNumber","messageCode"}) // Will only use this fields to generate equals.
public class ErrorMessage{
private long errorNumber;
private int numberOfParameters;
private Level loggingLevel;
private String messageCode;
Sehen Sie die Optionen avaliable anpassen, die in den Gleichen verwenden Felder. Lombok ist avalaible in Maven . Fügen Sie es einfach mit zur Verfügung gestellt Anwendungsbereich:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.14.8</version>
<scope>provided</scope>
</dependency>
in Android Studio alt + einfügen ---> gleich und hashCode
Beispiel:
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Proveedor proveedor = (Proveedor) o;
return getId() == proveedor.getId();
}
@Override
public int hashCode() {
return getId();
}
Bedenken Sie:
Object obj = new Book();
obj.equals("hi");
// Oh noes! What happens now? Can't call it with a String that isn't a Book...
die instanceOf
Aussage oft bei der Umsetzung von Gleichen verwendet wird.
Dies ist eine beliebte pitfall!
Das Problem ist, dass die Verwendung von instanceOf
die Regel Symmetrie verletzt:
(object1.equals(object2) == true)
, wenn und nur wenn (object2.equals(object1))
, wenn die erste gleich wahr ist, und object2 ist eine Instanz einer Unterklasse von die Klasse, in der obj1 gehört, dann die zweite equals wird return false
, wenn die betrachtete Klasse, wo ob1 gehört als final deklariert, dann ist diese Problem kann nicht auftreten, aber im Allgemeinen, sollten Sie testen, wie folgt:
this.getClass() != otherObject.getClass();
wenn nicht, return false, sonst Test
die Felder für die Gleichstellung vergleichen!
recordID ist Eigenschaft des Objekts
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Nai_record other = (Nai_record) obj;
if (recordId == null) {
if (other.recordId != null)
return false;
} else if (!recordId.equals(other.recordId))
return false;
return true;
}