Warum "implements Comparator" immer in separater Klassen soll?

oraclin25

Erfahrenes Mitglied
Hallo zusammen,

bei der Suche nach der Antwort meiner Frage, bin ich auf folgendes gestoßen:

My question is why cannot we just implement comparator, just like comparable and use a private function rather than inner class ?
Well (pretty much) the whole point of the Comparator interface is that an implementation of the interface is a separate class to the class of the objects being compared.

In theory you could do what you are suggesting, but the net result is counter-intuitive
Code:
public class MyKey implements Comparator<MyKey>{
            private String field;
         
            public boolean compare(MyKey m1, MyKey m2){
            // We must ignore this.field! We are comparing m1 and m2 ...
            return m1.field.compareTo(m2.field);
         }
}

MyKey[] keys =...
Arrays.sort(keys,newMyKey());
// Note we have to pass an instance to provide the Comparator.

In addition to being a bit counter-intuitive, your idea is limited in the sense that MyKey can only "provide" one comparator this way.

Frankly, if you are going to do this, it makes more sense to have MyKey implement Comparable<MyKey>.

Suppose that they had implemented String the way you proposed. Then this ...

Code:
String[] strings =newString[]{"a","c","B"};
Arrays.sort(strings);
... means sort case sensitive, but ...
Code:
String[] strings =newString[]{"a","c","B"};
Arrays.sort(strings,"weasel");
... would mean sort case insensitive. Does that really strike you as a good idea? Really?

Dass, man bei obiger Implementierung von Comparator lediglich EINEN Vergleicher hat, das ist verständlich. Aber was ich nicht verstehe, ist der letzte Satz:
... would mean sort case insensitive. Does that really strike you as a good idea? Really?
Warum soll dies nicht im Sinne eines sauberen Codings sein? Es ist doch in Ordnung so zu programmieren, oder?

Viele Grüße aus Rheinland,

Eure Ratna
 

sheel

I love Asm
Hi

der Text ist irreführend und teilweise einfach falsch.

Um das Ganze zu wiederholen:
Es gibt in Java einige DInge (wie zB. Arrays.sort,), die wissen wollen, wie die übergebenen Objekte zu vergleichen sind (für int, float usw. klar, aber nicht für irgendwelche selber geschriebenen Klassen). Damit das einheltlich ist gibt es zwei mögliche Interfaces: Wenn sie in die eigene Klasse eingebunden sind muss eine Vergleichsfunktion mit bestimmten Namen usw. exisiteren, und Zeug wie Arrays.sort nimmt nur Sachen, die diesen Interface eingebunden haben. Eins ist Comparable und eins Comparator, Arrays.sort und Ähnliches gibts für beide Varianten.

Comparable erfordert eine Methode "compareTo" in der eigenen Klasse K, die vergleicht das aktuelle Objekt (wo die Methode aufgerufen wird) und einem weiteren, das per Parameter übergeben wird.. Wenn man ein Objekt k1 hat und das zum Objekt k2 vergleichen will ist das ebenk1.compareTo(k2), und mit dem Returnwert hat man dann das Vergleichsergebnis.

Comparator hat einen etwas anderen Sinn: Eine Methode compare bekommt zwei Objekte von K und vergleicht die.
Die Methode compare muss natürlich auch in einer Klasse sein, aber das muss nicht unbedingt K sein: compare soll beim Vergleichen seine eigenes Objekt (wovon es aufgerufen wird) in Ruhe lassen. (Na gut, man könnte einen Comparator machen, der je nach gesetteter EInstellung anders vergleicht, dann müsse man natürlich die Einstellung abfragen. Egal) Wenn man also einen Comparator für K´s in einer anderen Klasse X macht kann man eben x1.compare(k1,k2) aufrufen (mit Objekten x1 von X und k1,k2 von K natürlich).

Der Comparator für K könnte auch in K selber sein. Das hat dann zwei Auswirkungen: Man braucht natürlich ein Objekt von k, um überhaupt Vergleichen zu können. Üblicherweise hat man ja schon zwei, die man Vergleichen will, man kann einfach eines davon nehmen. Also k1.compare(k1, k2). Man braucht keindrittes Objekt von k zum Vergleichen, wie der Text oben suggeriert, eins der Vergleichenden tuts auch. Nur ist das etwas seltsam, dass man k1 zu einer Methode von k1 übergibt.
Wenn man stattdessen ein drittes K-Objekt k3 hat, mit dem man k3.compare(k1, k2) machen will, könnte jemand beim Codelesen (wenn der sich nicht 100% sicher ist, was das tut) vermuten, dass k1/k2 irgendwie mit k3 verglcihen werden: Der Inhalt von k3 ist hier aber komplett egal, es soll nur die Methode compare bereitstellen. Aufgrund dieser "Irreführung" auch nicht so wirklich optimal.
=> Besser den Comparator in eine andere Klasse (statt K) tun.
(nochmal, der Text zeigt, dass man extra ein drittes Objekt zum Vergleichen erstellen müsste, falls man noch keins hat. Stimmt nicht. Wenn man kein drittes schon bereit k´hat kann man auch eins der zwei Vergleichenden nehmen. Nur ist der COmparator in K selber eben wie gesagt suboptimal.)

So, zum konkreten Beispiel aus dem Text:
Voraussetzungen:
Arrays.sort gibt es in einer 1-Parameter-Version, die nimmt ein Array von einer Klasse und verwendet deren comapreTo (Comparable, nicht Comparator) zum Vergleichen (also das, was ich ganz oben beschrieben habe, was nur in der Klasse selber Sinn macht)
Arrays.sort gibt es auch in einer 2-Parameter-Version, die nimmt ein Array von einer Klasse und noch einen Comparator (bzw. irgendein Objekt dieser oder einer anderen Klasse, das compare für die Klasse vom Array bereitstellt). Der Comparator wird zum Vergleichen verwendet
Die normale String-Klasse hat ein compareTo, aber kein Comparator-compare. Das compareTo vergleicht case-sensitive, also Groß/kleinbuchstaben A und a werden als verschieden betrachtet.

Der Text behauptet, dass
Java:
String[] strings = newString[]{"a","c","B"};
Arrays.sort(strings);
...dieses Array case-sensitive sortiert, also Groß/klein ist verschieden. Stimmt.

Der Text behauptet auch, dass, wenn String einen Comparator hätte,
Java:
String[] strings = newString[]{"a","c","B"};
Arrays.sort(strings,"weasel");
...dass das Array nicht case-sensitive sortiert. Stimmt nicht automatisch. Warum auch? Hängt ganz vom Inhalt der (gedachten) compare-Methode ab. Außerdem wird zu den 3 Strings im Array ein "weasel"-String gemacht, der die Methode compare liefern soll. Weasel ist unnötig.

(Wenn man von irgendwoher das zu sortierende Array bekommt und da zB. das Element [0] für compare verwenden will, statt Weasel, müsste man zuerst noch prüfen, ob das Array überhaupt ein Element hat (oder eben leer ist). Also Weasel ist zwar nicht nötig, aber macht das Codeschreiben evt. einfacher. Andererseits wirds auch verwirrter, jemand könnte sich fragen was "weasel" da zu bedeuten hat bzw. warum genau dieser String...)
 
Zuletzt bearbeitet:

oraclin25

Erfahrenes Mitglied
Hallo sheel,

vielen lieben Dank für die rasche Antwort. Ich freue mich über die Ausführlichkeit.
Mhh.. in der Tat, ich kapiere nicht, was "weasel" hier zu bedeuten hat. Es ist doch einfach ein String-Objekt? Wir nehmen also die compare-Methode von der String-Klasse, richtig?

Viele Grüße aus Rheinland,

Eure Ratna

edit:

och nee.. das stimmt so nicht. String implementiert die compare-Methode ja nicht. Mhh.. wofür ist "weasel" dann? Die 2-parametrige sort-Methode nimmt doch als 2. Parameter ein Objekt, das Comparator implementiert. "weasel" ist ein String-Objekt, das Comparator NICHT implementiert. Wo ist hier mein Denkfehler? :(

Eure Ratna
 
Zuletzt bearbeitet von einem Moderator:

sheel

I love Asm
Zum edit: Die Annahme beim Weasel-Beispiel ist ja, was wäre, *wenn* String einen Comparator in sich hat.

Alter Text:;
Genau. Der String könnte auch "muhaha" oder sonst was sein, oder auch newString[0]
(weil man da in dem Array ja schon drei String-Objekte hat), solang es ein String ist.

Dass das seltsam ist ist ja die Aussage vom Ganzen:
Ein String-objekt hat immer einen Wert (mindestens einen leeren 0-Buchstaben-String). Wenn jetzt String einen Comparator für sich selber in sich hätte müsste man zum Vergleichen von zwei Strings A und B immer schon einen String(wert) C haben, von dem man compare aufrufen kann. Und der Wert von den C ist für den Vergleich von A und B aber komplett egal, nur geben muss es ihn.

Deshalb macht es eben Sinn, compare in eine andere/eigene Klasse auszulagern,
die nicht gleichzeitig einen String/etc. beinhalten muss.
 

oraclin25

Erfahrenes Mitglied
aaaah.. so ist es also gemeint. vielen Dank sheel. Ich freue mich sehr, hab einen weiteren Aspekt wieder gelernt.:)
 

Neue Beiträge