1. Java objektumok összehasonlítása
Java-ban az objektumok referencia és érték alapján is összehasonlíthatók.
Referenciák összehasonlítása
Ha két változó ugyanarra az objektumra mutat a memóriában, akkor az ezekben a változókban tárolt hivatkozások egyenlőek. Ha összehasonlítja ezeket a változókat az egyenlőség operátorral ( ==
), akkor igaz lesz, és ez az eredmény logikus. Itt minden egyszerű.
Kód | Konzol kimenet |
---|---|
|
|
Összehasonlítás érték szerint
De gyakran találkozhatunk olyan helyzetekkel, amikor két változó két különböző objektumra utal, amelyek azonosak. Például két különböző karakterlánc-objektum, amelyek ugyanazt a szöveget tartalmazzák.
A módszer segítségével megállapíthatja, hogy a különböző objektumok azonosak-e equals()
. Például:
Kód | Konzol kimenet |
---|---|
|
|
A equals
módszer nem korlátozódik az osztályra String
. Minden osztálynak megvan.
Még olyan osztályok is, amelyeket egyedül írsz, és itt van miért.
2. Object
osztály
A Java minden osztálya örökli az Object
osztályt. A Java alkotói ezt a megközelítést találták ki.
És ha egy osztály örökli az Object
osztályt, akkor megkapja az osztály összes metódusát Object
. És ez az öröklődés egyik fő következménye.
Más szóval, minden osztály rendelkezik az osztály metódusaival Object
, még akkor is, ha a kódjuk nem említi őket.
Ezek az öröklött módszerek magukban foglalják az objektum-összehasonlításhoz kapcsolódó módszereket. Ezek a equals()
és hashCode()
módszerek.
Kód | A valóságban a következőkkel fogunk rendelkezni: |
---|---|
|
|
A fenti példában létrehoztunk egy egyszerű Person
osztályt név és életkor paraméterekkel, de nem egyetlen metódussal. De mivel minden osztály örökli az Object
osztályt, az Person
osztálynak automatikusan két metódusa van:
Módszer | Leírás |
---|---|
|
Összehasonlítja az aktuális objektumot és az átadott objektumot |
|
Az aktuális objektum hashkódját adja vissza |
Kiderült, hogy abszolút minden objektumnak megvan a equals
módszere, és a különböző típusú objektumok összehasonlíthatók egymással. Az ilyen kód lefordítható és tökéletesen működik.
Kód | Konzol kimenet |
---|---|
|
|
|
|
3. equals()
módszer
Az osztálytól equals()
örökölt metódus Object
a legegyszerűbb algoritmust valósítja meg az aktuális objektum és az átadott objektumok összehasonlítására: csak összehasonlítja az objektumokhoz való hivatkozásokat.
Ugyanezt az eredményt kapja, ha csak Person
a változókat hasonlítja össze a metódus meghívása helyett equals()
. Példa:
Kód | Konzol kimenet |
---|---|
|
|
Amikor a equals
metódus meghívásra kerül a
, egyszerűen összehasonlítja a változóban tárolt referenciát a
a változóban tárolt hivatkozással b
.
Az összehasonlítás azonban másként működik az osztályban String
. Miért?
Mert az emberek, akik létrehozták az String
osztályt, megírták a saját módszerüket equals()
.
equals()
A módszer megvalósítása
Most írjuk meg az egyenlőség metódus saját implementációját az osztályba Person
. 4 fő esetet fogunk megvizsgálni.
equals
metódust, mindig egy objektumot vesz fel Object
argumentumként
1. forgatókönyv : ugyanaz az objektum, amelyen a equals
metódus meghívásra kerül, szintén átadásra kerül a equals
metódusnak. Ha az aktuális objektum és az átadott objektum hivatkozásai megegyeznek, a metódusnak vissza kell térnie true
. Egy tárgy egyenlő önmagával.
Kódban így fog kinézni:
Kód | Leírás |
---|---|
|
Hasonlítsa össze a referenciákat |
2. forgatókönyv : null
átkerül a equals
metódushoz – nincs mihez hasonlítanunk. Az objektum, amelyen a metódus meghívódik, biztosan nem null, ezért ebben az esetben equals
vissza kell térnünk .false
Kódban így fog kinézni:
Kód | Leírás |
---|---|
|
Referenciák összehasonlítása Az átadott objektum null ? |
3. forgatókönyv : egy olyan objektumra való hivatkozás, amely nem a, Person
átadásra kerül a equals
metódusnak. Az Person
objektum egyenlő a nem tárggyal Person
? Ezt a kérdést az osztály fejlesztőjének Person
kell eldöntenie, ahogy akarja.
De általában az objektumoknak ugyanabba az osztályba kell tartozniuk, hogy egyenlőnek tekintsék őket. Ezért, ha az osztály objektumán kívül mást is Person
átadunk az equals metódusunknak, akkor mindig a -t adjuk vissza false
. Hogyan ellenőrizheti egy objektum típusát? Így van – az operátor használatával instanceof
.
Így néz ki az új kódunk:
Kód | Leírás |
---|---|
|
Referenciák összehasonlítása Az átadott objektum null ? Ha az átadott objektum nem a Person |
Person
4. Két objektum összehasonlítása
Mire jutottunk? Ha a metódus végére értünk, akkor van egy Person
objektumhivatkozásunk, amely nem null
. Tehát konvertáljuk a-ba, Person
és összehasonlítjuk mindkét objektum releváns belső adatait. És ez a negyedik forgatókönyvünk .
Kód | Leírás |
---|---|
|
Referenciák összehasonlítása Az átadott objektum null ? Ha az átadott objektum nem Person Typecasting |
És hogyan lehet összehasonlítani két Person
tárgyat? Egyenlőek, ha azonos a nevük ( name
) és az életkoruk ( age
). A végső kód így fog kinézni:
Kód | Leírás |
---|---|
|
Referenciák összehasonlítása Az átadott objektum null ? Ha az átadott objektum nem Person Typecasting |
De ez még nem minden.
Először is, a név mező egy String
, ezért a névmezőt a metódus meghívásával kell összehasonlítani equals
.
this.name.equals(person.name)
Másodszor, a name
mező lehet null
: ebben az esetben nem hívhatja equals
meg. További ellenőrzésre van szüksége null
:
this.name != null && this.name.equals(person.name)
Ez azt jelenti, hogy ha a névmező null
mindkét Person
objektumban szerepel, akkor a nevek továbbra is azonosak.
A negyedik forgatókönyv kódja így nézhet ki:
|
Ha az életkorok nem egyenlőek, azonnal return false If this.name egyenlő -val null , akkor nincs értelme a equals módszerrel összehasonlítani. Itt vagy name egyenlő a második mezővel null , vagy nem. Hasonlítsa össze a két névmezőt a equals metódus segítségével. |
5. hashCode()
módszer
A két objektum összes mezőjének részletes összehasonlítását célzó módszer mellett equals
van egy másik módszer is, amely pontatlan, de nagyon gyors összehasonlításra használható: hashCode()
.
Képzelje el, hogy ábécé sorrendben rendezi a több ezer szóból álló listát, és ismételten össze kell hasonlítania a szópárokat. És a szavak hosszúak, sok betűből állnak. Általánosságban elmondható, hogy egy ilyen összehasonlítás nagyon sokáig tartana.
De fel lehet gyorsítani. Tegyük fel, hogy vannak olyan szavaink, amelyek különböző betűkkel kezdődnek – azonnal világos, hogy különböznek. De ha ugyanazokkal a betűkkel kezdődnek, akkor még nem tudjuk megmondani, mi lesz az eredmény: előfordulhat, hogy a szavak azonosak vagy eltérőek.
A hashCode()
módszer hasonló elven működik. Ha egy objektumra hívja, akkor valamilyen számot ad vissza – hasonlóan a szó első betűjéhez. Ez a szám a következő tulajdonságokkal rendelkezik:
- Az azonos objektumoknak mindig ugyanaz a hashcode
- A különböző objektumok ugyanazzal a hashkóddal rendelkezhetnek, vagy a hashkódjaik eltérőek lehetnek
- Ha az objektumok különböző hashkódokkal rendelkeznek, akkor az objektumok határozottan mások
Hogy ez még egyértelműbb legyen, fogalmazzuk át ezeket a tulajdonságokat szavakkal:
- Az azonos szavak kezdőbetűi mindig ugyanazok.
- Különböző szavak kezdőbetűi lehetnek azonosak, vagy az első betűik eltérőek lehetnek
- Ha a szavak kezdőbetűi eltérőek, akkor a szavak határozottan mások
Az utolsó tulajdonság az objektumok összehasonlításának felgyorsítására szolgál:
Először a két objektum hashkódját számítjuk ki. Ha ezek a hashkódok különböznek, akkor az objektumok határozottan mások, és nincs szükség további összehasonlításra.
De ha a hashkódok megegyeznek, akkor is össze kell hasonlítanunk az objektumokat az egyenlőség metódusával.
6. Szerződések kódban
A fent leírt viselkedést minden Java osztálynak meg kell valósítania. A fordítás során nincs mód annak ellenőrzésére, hogy az objektumok megfelelően vannak-e összehasonlítva.
A Java programozóknak van egy egyetemes megállapodásuk, miszerint ha saját maguk írják meg az equals() metódus implementációját, és ezzel felülírják a szabványos implementációt (az osztályban Object
), akkor a metódus saját implementációját is meg kell írniuk hashCode()
úgy, hogy a fent említett szabályok elégedett.
Ezt a megállapodást szerződésnek nevezik .
equals()
Ha csak a vagy csak a metódust alkalmazod hashCode()
az osztályodban, akkor durván megszeged a szerződést (megszegted a megállapodást). Ne csináld ezt.
Ha más programozók használják az Ön kódját, előfordulhat, hogy nem működik megfelelően. Mi több, olyan kódot fog használni, amely a fenti szerződések betartásán alapul.
Egy elem keresésekor az összes Java gyűjtemény először az objektumok hashkódjait hasonlítja össze, és csak ezután végez összehasonlítást a metódussal equals
.
Ez azt jelenti, hogy ha adsz egy equals
metódust a saját osztályodnak, de nem írod meg a saját metódusodat hashCode()
, vagy nem megfelelően implementálod, akkor előfordulhat, hogy a gyűjtemények nem működnek megfelelően az objektumokkal.
Például hozzáadhat egy objektumot egy listához, majd megkeresheti a metódussal contains()
, de előfordulhat, hogy a gyűjtemény nem találja meg az objektumot.