Trochu mě zarazilo, proč musí být při použití Arrays.sort překryta metoda equals tak, aby vracela true pro compareTo(...) == 0. Pokud vím, compareTo je součástí interfacu Comparable a tedy při použití komparátoru toto nepoužiji. Nebo se mýlím? Předpokládám, že v komparátoru, který funkci Arrays.sort předávám, nepotřebuji metodu compareTo nebo equals. Od toho tuším komparátor je.
Přiznámvám se ale, že v Javě natolik zběhlý nejsem, proto pokud je tam nějaký důvod, který nevidím, budu rád, když se jej dovím.
Mate pravdu, v textu ma byt compare() nikoli compareTo(), omlouvam se za zmateni.
Pri pouziti Arrays.sort() NEMUSI byt equals() prekryta, a to ani pri pouziti komparatoru ani v pripade, ze trida, jejiz instance se radi, implementuje rozhrani Comparable a tedy i metodu compareTo().
Konkretne zde je implementace Arrays.sort() zavolana v pripade, ze se teto metode preda krome pole i komparator. Zadne equals() se zde nevola, pouze compare():
private static void mergeSort(Object[] src,
Object[] dest,
int low, int high, int off,
Comparator c) {
int length = high - low;
// Insertion sort on smallest arrays
if (length < INSERTIONSORT_THRESHOLD) {
for (int i=low; i<high; i++)
for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
swap(dest, j, j-1);
return;
}
// Recursively sort halves of dest into src
int destLow = low;
int destHigh = high;
low += off;
high += off;
int mid = (low + high) >>> 1;
mergeSort(dest, src, low, mid, -off, c);
mergeSort(dest, src, mid, high, -off, c);
// If list is already sorted, just copy from src to dest. This is an
// optimization that results in faster sorts for nearly ordered lists.
if (c.compare(src[mid-1], src[mid]) <= 0) {
System.arraycopy(src, low, dest, destLow, length);
return;
}
// Merge sorted halves (now in src) into dest
for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
dest[i] = src[p++];
else
dest[i] = src[q++];
}
}
Ta metoda Comparator.equals je na zmateni nepritele, a tentokrat se to povedlo. Slouzi k porovnani dvou comparatoru a nema VUBEC nic spolecnyho s metodou compare.
To ze je equals uvedeny v interfejsu Comparator nedava skoro zadny smysl, pridanou hodnotou (a to spornou) je pouze komentar k ni. Vzhledem k tomu ze equals je podedeny od Object, je Comparator stale (takovy divny) SAM interfejs.
Tu si to autor mohol dovolit. Teda ak predpokladame, ze ani vek ani plat nemoze byt zaporny. Ak by ale mohol, pri odcitavani moze dojst k preteceniu. Kto neveri nech vyskusa toto:
public static void main(String[] args) {
int i1 = Integer.MIN_VALUE;
int i2 = 1;
System.out.println(i1 - i2); // tu by compare vratilo nespravny vysledok!
System.out.println((long) i1 - (long) i2);
}
"...je žádoucí přetížit i metodu equals(), a to takovým způsobem, aby tato metoda vracela hodnotu true v případě, že metoda compareTo() vrací nulu."
Tohle platí, ovšem přesně obráceně: Jestliže equals vrátí true, compareTo musí vrátit nulu.
Kdyby měla být aplikována autorova poučka na jeho příklad s rodnými čísly (compareTo vrací nulu v případě shody číslic před lomítkem), pak by equals vracela true pro lidi stejného pohlaví narozené v tentýž den (+ lidi narozené v okolních stoletích). Což je v případě použití rodného čísla například jako klíče v java.util.Map docela děsivá představa.
Pokud se pouze pretizi equals(), tak to pracovat bude, protoze se pri pristupu k prvkum nejdrive kontroluje hashCode(), ktery musi byt shodny soucasne s equals(). I kdyz se samozrejme jedna o krehky kod, ktery zavisi na tom, ze hashCode() pro kazda dve sestimistna cisla je rozdilny - coz je, ale pro jine JDK to nemusi platit ;-)
Je dobré neplést pojmy "přetížit" (overload) a "překrýt" (override). Přetížení metody equals() nevede k očekávanému výsledku (naopak může vést k velmi špatně vystopovatelné chybě), překrytí ano. Z kontextu je jasné, jak to myslíte, ale může to být dosti zavádějící.
Dále z textu není patrné, zda by měl člověk překrýt metodu equals() na komparátoru, nebo ve třídě Employee. Metoda Comparator.equals(Object) já trošku jinou sémantiku než Object.equals(Object).
A když už jsem za hnidopicha, tak ještě jedna drobnost. :-) Pojmy "třídit" a "řadit" v češtině znamenají něco jiného. Třídíme odpad, řadíme studenty podle jména.
Kdyz uz jsme u JCP, tady je jedna cerstva zpravicka https://blogs.apache.org/foundation/entry/the_asf_resigns_from_the
Apache foundation melo dost dobre napady, jakym smerem Javu rozsirovat, tak uvidime, co udelaji dale.