Porovnávání a pořadí (uspořádání)
-
Obecně rozlišujeme, zda chceme zjišťovat shodnost (rovnost, ekvivalenci) mezi dvěma primitivními hodnotami nebo objekty, či nás zajímá,
-
v jakém pořadí (uspořádání) hodnoty či objekty jsou, tzn. která/ý je dříve-později, evt. menší-větší.
-
Zajímco u primitivních hodnot je jak rovnost tak pořadí určeno Javou napevno a nelze je programově změnit,
-
u objektů lze u některých porovnání/uspořádání chování programově určovat.
Rovnost primitivních hodnot
-
Rovnost/nerovnost primitivních hodnot zjišťujeme pomocí operátorů
==
(rovná se),!=
(nerovná se) -
U integrálních typů funguje bez potíží
-
U čísel floating-point (
double
,float
) je většinou třeba porovnávat s určitou tolerancí, tzn. brát za rovná čísla odlišná o méně než jistédelta
Uspořádání primitivních hodnot
-
Uspořádání primitivních hodnot, tzn. určení, která hodnota je menší/větší zjišťujeme pomocí operátorů
<
,<=
,>=
,>
-
Uspořádání není definováno na typu
boolean
, tzn. není určeno, zdafalse < true
-
U primitivních hodnot nelze koncept uspořádání ani rovnosti programově měnit.
Jak chápat rovnost objektů
- Identita objektů
-
==
vracítrue
právě při rovnosti odkazů, neboli když oba odkazy ukazují na přesně tentýž objekt, tj. jsou-li objekty identické. Odkazy obsahují tutéž adresu objektu. - Rovnost obsahu
-
tedy jakási rovnocennost, rovnost obsahu, ekvivalence objektů se zjišťuje voláním metody
o1.equals(Object o2)
Porovnávání objektů pomocí ==
Použití ==
na objekty:
-
Porovnáme-li dva objekty (tzn. odkazy na objekty) prostřednictvím operátoru
==
dostaneme rovnost jen v případě, jedná-li se o dva odkazy na tentýž objekt — tj. dva totožné objekty. -
Jedná-li se o dva byť obsahově stejné objekty, ale existující samostatně, pak
==
vrátífalse
.
Porovnávání objektů dle obsahu
-
Chceme-li (intuitivně) chápat rovnost objektů podle obsahu, tj.
-
dva objekty jsou rovné (rovnocenné, nikoli totožné), mají-li stejný obsah, pak
-
musíme pro danou třídu překrýt metodu
equals
, která musí vrátittrue
, právě když se obsah výchozího a srovnávaného objektu rovná. -
Fungování
equals
lze srovnat s porovnáváním dvou databázových záznamů podle primárního klíče. -
Nepřekryjeme-li
equals
, funguje původníequals
přísným způsobem, tj. rovné si budou jen totožné objekty .
Příklad porovnávání objektů
Objekt třídy Person
nese informace o člověku.
Zde dva objekty položíme stejné (rovnocenné),
nesou-li stejná příjmení.
public class Person { private String firstname; private String surname; public Person (String j, String p) { firstname = j; surname = p; } public boolean equals(Object o) { if (o instanceof Person) { Person c = (Person)o; // dva lidé se rovnají, mají-li stejná příjmení return surname.equals(c.surname); } else { // porovnáváme-li osobu s ne-osobou... return false; } } }
Metoda hashCode
S překrytím metody equals
vyvstává jeden dosud nezmíněný problém:
-
Jakmile u třídy překryjeme metodu
equals
, měli bychom současně překrýt i metoduhashCode
. Tato metoda vrací celé číslo (int
) co nejlépe charakterizující obsah objektu tak, aby: — pro dva stejné (dleequals
) objekty musí vždy vrátit stejnou hodnotu. — Pro dva obsahově různé objekty byhashCode
naopak měla vracet různé hodnoty (což ale není stoprocentně nezbytné a ani nemůže být vždy splněno).
Note
|
Metoda |
Příklad hashCode
-
V těle
hashCode
námi definované třídy s oblibou delegujeme řešení na voláníhashCode
jednotlivých složek našeho objektu -
a to těch, které figurují v
equals
. Rozšíříme minulý příklad.public class Person { private String firstname; private String surname; public Person (String firstname, String surname) { this.firstname = firstname; this.surname = surname; } public boolean equals(Object o) { // zde zůstává porovnání příjmení } // nyní ale doplňujeme překrytí hashCode public int hashCode() { // které využívá volání hashCode na příjmení, // protože jedině příjmení využíváme v equals return surname.hashCode(); } }