Komparator-und equals()
Nehme an, ich brauche TreeSet
mit Elementen sortiert mit einigen Domänen-Logik. Durch diese Logik ist es egal, um einige Elemente, die nicht gleich so vergleichen, können Sie die Methode 0 zurück, aber in diesem Fall konnte ich nicht setzen Sie Sie in TreeSet
.
So, Frage: welche Nachteile werde ich haben aus code wie folgt:
class Foo implements Comparable<Foo>{}
new TreeSet<Foo>(new Comparator<Foo>(){
@Override
public int compare(Foo o1, Foo o2) {
int res = o1.compareTo(o2);
if(res == 0 || !o1.equals(o2)){
return o1.hashCode() - o2.hashCode();
}
return res;
}
});
Update:
Ok. Wenn sollte es immer sein, eine Konsistenz zwischen den Methoden equals()
, hashcode()
und compareTo()
, wie @S. P. Floyd - seanizer und andere sagten.
Wäre es besser oder sogar gut, wenn werde ich entfernen Comparable
- Schnittstelle und verschieben Sie diese Logik in Comparator
(ich kann es tun, ohne gebrochen Kapselung)? So wird es sein:
class Foo{}
new TreeSet<Foo>(new Comparator<Foo>(){
@Override
public int compare(Foo o1, Foo o2) {
//some logic start
if(strictliBigger(o1, o2)){ return 1;}
if(strictliBigger(o2, o1)){ return -1;}
//some logic end
if(res == 0 || !o1.equals(o2)){
return o1.hashCode() - o2.hashCode();
}
return res;
}
});
Update 2:
Würde System.identityHashCode(x)
besser sein, als hashCode()
wenn ich Sie nicht brauche stabile Sortieren?
Elite Gentleman, ja.
einer dieser kehrt nach
strictliBigger
sollte -1 seinseanizer, Danke. Behoben.
InformationsquelleAutor Stan Kurilin | 2010-12-03
Du musst angemeldet sein, um einen Kommentar abzugeben.
Während dies funktionieren könnte, es ist weit von einer best practice.
Aus der SortedSet docs:
Für Objekte, die Umsetzung
Comparable
sollte es immer eine übereinstimmung zwischen den Methodenequals()
,hashcode()
undcompareTo()
.Ich fürchte, ich komme
SortedSet
ist einfach nicht das, was Sie wollen, noch eine GuaveMultiSet
angemessen sein (denn es wird nicht lassen Sie Sie selbständig abrufen mehrerer gleicher Artikel). Ich denke, dass das, was Sie brauchen, ist einSortedList
. Es gibt keine solche Tier, das ich kenne (vielleicht in commons-collections, aber die sind ein bisschen auf der legacy-Seite), so dass ich realisiert für Sie mit Guave - ForwardingList als Basisklasse. Kurz gesagt: diese Liste Delegierten fast alles, was zu einemArrayList
es intern verwendet, aber es verwendetCollections.binarySearch()
imadd()
Methode, um die richtige Einfügeposition, und es wirft einUnsupportedOperationException
auf alle optionalen Methoden derList
undListIterator
Schnittstellen, add-oder set-Werte an einer gegebenen position.Die Konstruktoren sind identisch mit denen von
ArrayList
, aber für jeden von Ihnen gibt es auch eine zweite version mit einem customComparator
. Wenn Sie nicht verwenden Sie eine benutzerdefinierte Komparator, Ihre Liste Elemente implementieren müssenComparable
oderRuntimeException
s auftreten während der Sortierung.Ich aktualisiert meine Antwort. Ein SortedSet ist wahrscheinlich nicht das richtige für Sie.
Oh. Heute geben Sie den code der zwei Klassen für mich. Vielen Dank.
kein prob, Umsetzung Guave-basierten Klassen, die Spaß macht 🙂
Sehr nett von dir. +1
InformationsquelleAutor Sean Patrick Floyd
Vorsicht: auch für zwei Foos
f1
,f2
mitf1 != f2
Sie bekommen konntef1.hashCode() == f2.hashCode()
! Das bedeutet, dass Sie nicht bekommen eine stabile Sortierung mit Ihremcompare
Methode.Ich brauche nicht stabile Sortierung)
InformationsquelleAutor Thomas
Gibt es keine Regel in Java, die sagt, dass die hash-codes der beiden Objekte müssen Verschieden sein, nur weil Sie nicht gleich (also
o1.hashCode() - o2.hashCode()
zurückkehren konnte0
in Ihrem Fall).Auch das Verhalten der
equals()
sollte werden im Einklang mit den Ergebnissen voncompareTo()
. Dies ist nicht eine muss aber wenn Sie es nicht durchhalten, es deutet darauf hin, dass Ihr design hat ein großes Manko.Empfehle ich, einen Blick auf die anderen Felder der Objekte und verwenden Sie einige von diesen zu erweitern, Ihre-Vergleich so erhalten Sie einen Wert
!= 0
für Objekte warenequals() == false
.Die Logik ist fehlerhaft; es spielt keine Rolle, wo Sie es ausdrückte.
InformationsquelleAutor Aaron Digulla
hashcode()
Methode nicht garantierenless than
odergreater than
.compare()
undequals()
Rendite die gleiche Bedeutung, aber es ist nicht erforderlich, obwohl.Soweit kann ich verstehen, aus Ihrer verwirrenden code (nichts für ungut :)), die Sie hinzufügen möchten Duplikaten
TreeSet
. Aus diesem Grund werden Sie kam mit dieser Umsetzung. Hier ist der Grund, Sie können Sie nicht in derTreeSet
, zitierte die docs,So, müssen Sie etwas tun, mit yor
equals()
Methode, so kann es nie wieder wahr, was so überhaupt. Die beste Umsetzung wäre,Übrigens, wenn ich es richtig in meinem Verständnis, warum nicht Sie verwenden
List
statt und Sortieren.Frage aktualisiert.
InformationsquelleAutor Adeel Ansari
Sehr interessante Frage.
Soweit ich dein problem verstanden ist doppelte Elemente zu.
Ich denke, dass, wenn o1.equals(o2) deren hash-codes könnten gleich zu. Es hängt von der Implementierung der hashCode() in der Klasse "Foo". Also, ich würde vorschlagen, Sie verwenden System.identityHashCode(x) statt.
InformationsquelleAutor AlexR
Haben Sie eine
Foo
Klasse wich vergleichbar ist, aber zur Sortierung in einemTreeSet<Foo>
Struktur. Dann deine Idee ist der richtige Weg, es zu tun. Verwenden Sie diesen Konstruktor, um zu "überstimmen" die Natürliche Sortierung vonFoo
.InformationsquelleAutor Andreas_D
Wenn Sie keine speziellen erwartet, dass die Bestellung für zwei beliebige Elemente gegeben, aber immer noch wollen, um Sie zu betrachten, un-gleich, dann haben Sie wieder einige angegebene Bestellung sowieso.
So, wie andere geschrieben haben,
hashCode()
ist nicht ein guter Kandidat, weil diehashCode()
Werte beider Elemente können ganz einfach gleich.System.identityHashCode()
wäre die bessere Wahl, aber ist noch nicht perfekt, wie auchidentityHashCode()
garantiert nicht eindeutige Werte entwederDen Guave
arbitrary()
Bestellung implementiert eineComparator
mitSystem.identityHashCode()
.InformationsquelleAutor Joachim Sauer
Ja, wie andere schon oben gesagt, hashCode() nicht sicher ist, hier zu verwenden. Aber wenn Sie dont care über die Reihenfolge der Objekte, die gleich sind in Bezug auf o1.compareTo(o2) == 0 ist, konnten Sie etwas wie:
InformationsquelleAutor morja
Kann problematisch sein, da wenn 2 Objekte gleich sind (d.h. in Ihrem
res == 0
) dann diese 2 Objekte wieder den gleichen hashcode. Hashcodes sind nicht einzigartig für jedes Objekt.Bearbeiten @Stas, Die
System.identityHashCode(Object x);
noch nicht helfen. Der Grund ist beschrieben auf der javadoc:siehe meine aktualisierte Antwort.
Elite Gentleman, ich verstehe es nicht. Wenn es zwei verschiedene Objekte, die Ihre Standard -
hashCode()
anders sein würde mit hoher Wahrscheinlichkeit.Es bedeutet einfach, dass
System.identityHashCode()
gibt (x.hashCode()
). Also, in deinem Fall macht es keinen Unterschied, ob Sieo1.hashCode()
oderSystem.identityHashCode(o1)
.Elite Gentleman, vielen Dank, jetzt sehe ich.
InformationsquelleAutor Buhake Sindi
Gibt es ein paar Probleme hier:
Hash-codes sind im Allgemeinen nicht eindeutig, und insbesondere
System.identityHashCode
nicht einzigartig auf vage modernen JVMs.Dies ist nicht eine Frage der Stabilität. Wir Sortieren eines Arrays, sondern die Schaffung einer Baumstruktur. Die hash-code-Kollisionen verursachen
compare
zu null zurückgeben, die fürTreeSet
bedeutet, dass ein Objekt gewinnt und die andere verworfen wird - es wird nicht degradieren zu einer verketteten Liste (der clue ist, dass Sie "Set" im Namen).Es ist in der Regel ein integer-überlauf-Problem mit Subtraktion eines hash-code aus einem anderen. Dies bedeutet, dass der Vergleich nicht transitiv (d.h. es ist kaputt). Da Glück es haben würde, auf die Sun/Oracle-Implementierung
System.identityHashCode
gibt immer positive Werte. Dies bedeutet, dass umfangreiche Tests, werden wahrscheinlich nicht finden, diese Besondere Art von Fehler.Glaube ich nicht, es ist ein guter Weg, dies zu erreichen mit
TreeSet
.InformationsquelleAutor Tom Hawtin - tackline
Zwei Punkte relevant sein könnten, und diese sind, dass die Rückkehr in eine situation dargestellt, als -1 und das hängt davon ab, ob ein negativer Wert ist, dürfen in der Funktion parameter-variable oder des betreffenden Landes von nutzen, und auch wenn die Methode, die Sie verwenden ist nicht gestattet. Es sind standard-Daten-Vermittlung-Methoden wie Auswahl oder Auswahl Sortieren und Papier Beschreibung oder code wird in der Regel von einer nationalen Behörde, wenn eine Kopie nicht an Ihrem Arbeitsplatz. Mit Vergleiche wie größer oder kleiner als die Geschwindigkeit des Codes und vermeidet die Verwendung von einem direkten Vergleich für die Gleichstellung von stillschweigenden dropthrough, um Sie später zu Skripts oder code.
InformationsquelleAutor Developer