Java, Warum wird vorausgesetzt, dass Objekte gleich sind, wenn compareTo () 0 zurückgibt?
Let ' s haben einen Klasse Person
. Person hat einen Namen und Höhe.
Equals-und hashCode() berücksichtigt nur die Namen. Person vergleichbar ist (oder wir implementieren Komparator für es, ist egal welche). Personen werden verglichen, indem die Höhe.
Scheint es vernünftig zu erwarten, dass eine situation, wo zwei verschiedene Personen haben gleiche Höhe, aber zB. TreeSet verhält sich wie comapareTo()==0 bedeutet gleich, die nicht nur gleiche Größe.
Um dies zu vermeiden, den Vergleich kann Sekundär zu betrachten, etwas anderes, wenn Größe ist die gleiche, aber dann kann es nicht verwendet werden, zu erkennen gleicher Größe von verschiedenen Objekten.
Beispiel:
import java.util.Comparator;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
public class Person implements Comparable<Person> {
private final String name;
private int height;
public Person(String name,
int height) {
this.name = name;
this.height = height;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public String getName() {
return name;
}
@Override
public int compareTo(Person o) {
return Integer.compare(height, o.height);
}
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Person other = (Person) obj;
if (!Objects.equals(this.name, other.name)) {
return false;
}
return true;
}
public int hashCode() {
int hash = 5;
hash = 13 * hash + Objects.hashCode(this.name);
return hash;
}
public String toString() {
return "Person{" + name + ", height = " + height + '}';
}
public static class PComparator1 implements Comparator<Person> {
@Override
public int compare(Person o1,
Person o2) {
return o1.compareTo(o2);
}
}
public static class PComparator2 implements Comparator<Person> {
@Override
public int compare(Person o1,
Person o2) {
int r = Integer.compare(o1.height, o2.height);
return r == 0 ? o1.name.compareTo(o2.name) : r;
}
}
public static void test(Set<Person> ps) {
ps.add(new Person("Ann", 150));
ps.add(new Person("Jane", 150));
ps.add(new Person("John", 180));
System.out.println(ps.getClass().getName());
for (Person p : ps) {
System.out.println(" " + p);
}
}
public static void main(String[] args) {
test(new HashSet<Person>());
test(new TreeSet<Person>());
test(new TreeSet<>(new PComparator1()));
test(new TreeSet<>(new PComparator2()));
}
}
Ergebnis:
java.util.HashSet
Person{Ann, height = 150}
Person{John, height = 180}
Person{Jane, height = 150}
java.util.TreeSet
Person{Ann, height = 150}
Person{John, height = 180}
java.util.TreeSet
Person{Ann, height = 150}
Person{John, height = 180}
java.util.TreeSet
Person{Ann, height = 150}
Person{Jane, height = 150}
Person{John, height = 180}
Haben Sie eine Idee, warum es so ist?
InformationsquelleAutor der Frage Alpedar | 2011-08-29
Du musst angemeldet sein, um einen Kommentar abzugeben.
Auszug aus der
java.util.SortedSet
javadoc:Also, in anderen Worten,
SortedSet
Pausen (oder "erweitert") die Allgemeinen Verträge fürObject.equals()
undComparable.compareTo
. Finden Sie den Vertrag fürcompareTo
:InformationsquelleAutor der Antwort Lukas Eder
Es wird empfohlen, dass
compareTo
gibt nur0
wenn ein Anruf zuequals
auf die gleichen Objekte zurücktrue
:(Aus der JDK 1.6 Javadocs)
InformationsquelleAutor der Antwort nfechner
TreeSet
funktioniert nicht mit hash-codes und Gleichheit - es funktioniert nur auf der Grundlage des Komparators, die es Ihnen. Beachten Sie, dass die Javadoc Staaten:In Ihrem Fall, Ihr Vergleich *nicht im Einklang mit
equals
so dass Ihr set nicht gehorchen dem Allgemeinen Vertrag für dieSet
.Warum nicht fügen Sie einfach weitere Aspekte für den Vergleich, so dass nur gleiche Elemente vergleichen mit einem Ergebnis von 0?
InformationsquelleAutor der Antwort Jon Skeet
können Sie es beheben, indem man den Namen für einen anderen Vergleich, wenn die Höhen gleich sind
da die Namen eindeutig sind, wird dies nur gibt 0 zurück, wenn
this.equals(o)
InformationsquelleAutor der Antwort ratchet freak
Es wird dringend empfohlen, ist aber nicht streng erforderlich, dass
(x.compareTo(y)==0) == (x.equals(y))
[Eins]So ist es fein, dass du im Vergleich mit anderen Kriterien als die verwendet werden auf
equals
gewährt, die Sie dokumentieren.Aber es wäre besser, wenn Ihr zu vergleichen, durch die gleichen Kriterien und, falls erforderlich, geben Sie einen benutzerdefinierten Komparator, die sich auf die neuen Kriterien ( Höhe in dem Fall der Mensch )
InformationsquelleAutor der Antwort OscarRyz
Geben, wenn Sie Person, die einen Komparator, der vergleicht Instanzen auf das height-Attribut der Person, es wirklich bedeutet, dass zwei-Personen-Instanzen sind gleich, wenn Sie die gleiche Höhe haben.
Sie haben zu einem Komparator, der spezifisch ist für die Klasse Person.
InformationsquelleAutor der Antwort S.L. Barth