1. Compararea obiectelor în Java
În Java, obiectele pot fi comparate atât prin referință, cât și prin valoare.
Compararea referințelor
Dacă două variabile indică același obiect din memorie, atunci referințele stocate în aceste variabile sunt egale. Dacă comparați aceste variabile folosind operatorul de egalitate ( ==
), obțineți adevărat și rezultatul are sens. Totul este simplu aici.
Cod | Ieșire de consolă |
---|---|
|
|
Compararea după valoare
Dar puteți întâlni adesea situații în care două variabile se referă la două obiecte distincte care sunt identice. De exemplu, două șiruri diferite de obiecte care conțin același text.
Pentru a determina dacă diferite obiecte sunt identice, utilizați equals()
metoda. De exemplu:
Cod | Ieșire de consolă |
---|---|
|
|
Metoda equals
nu se limitează la String
clasă. Fiecare clasă o are.
Chiar și cursuri pe care le scrii singur și iată de ce.
2. Object
clasa
Toate clasele din Java moștenesc Object
clasa. Creatorii lui Java au venit cu această abordare.
Și dacă o clasă moștenește Object
clasa, atunci câștigă toate metodele clasei Object
. Și aceasta este o consecință majoră a moștenirii.
Cu alte cuvinte, fiecare clasă are metodele clasei Object
, chiar dacă codul lor nu le menționează.
Aceste metode moștenite includ metode legate de compararea obiectelor. Acestea sunt metodele equals()
și hashCode()
.
Cod | În realitate, iată ce vom avea: |
---|---|
|
|
În exemplul de mai sus, am creat o Person
clasă simplă cu parametri de nume și vârstă, dar nu o singură metodă. Dar, deoarece toate clasele moștenesc Object
clasa, Person
clasa are automat două metode:
Metodă | Descriere |
---|---|
|
Compară obiectul curent și obiectul trecut |
|
Returnează codul hash al obiectului curent |
Se pare că absolut fiecare obiect are equals
metoda, iar obiectele de diferite tipuri pot fi comparate între ele. Un astfel de cod se va compila și va funcționa perfect.
Cod | Ieșire de consolă |
---|---|
|
|
|
|
3. equals()
metoda
Metoda equals()
, moștenită de la Object
clasă, implementează cel mai simplu algoritm pentru compararea obiectului curent cu obiectele trecute: doar compară referințele la obiecte.
Obțineți același rezultat dacă doar comparați Person
variabile în loc să apelați equals()
metoda. Exemplu:
Cod | Ieșire de consolă |
---|---|
|
|
Când equals
metoda este apelată pe a
, ea pur și simplu compară referința stocată în a
variabilă cu referința stocată în b
variabilă.
Cu toate acestea, comparația funcționează diferit pentru String
clasă. De ce?
Pentru că cei care au creat String
clasa și-au scris propria implementare a equals()
metodei.
Implementarea equals()
metodei
Acum să scriem propria noastră implementare a metodei equals în Person
clasă. Vom lua în considerare 4 cazuri principale.
equals
metoda, aceasta ia întotdeauna un Object
obiect ca argument
Scenariul 1 : același obiect pe care equals
este apelată metoda este de asemenea transmis metodei equals
. Dacă referințele obiectului curent și ale obiectului trecut sunt egale, metoda trebuie să returneze true
. Un obiect este egal cu el însuși.
În cod va arăta astfel:
Cod | Descriere |
---|---|
|
Comparați referințele |
Scenariul 2 : null
este trecut la equals
metodă — nu avem cu ce să comparăm. Obiectul pe care equals
este apelată metoda nu este cu siguranță nul, așa că trebuie să revenim false
în acest caz.
În cod va arăta astfel:
Cod | Descriere |
---|---|
|
Comparare referințe Este obiectul trecut null ? |
Scenariul 3 : o referință la un obiect care nu este un Person
este transmisă metodei equals
. Este Person
obiectul egal cu non- Person
obiectul? Aceasta este o întrebare pentru care dezvoltatorul clasei Person
trebuie să decidă cum dorește.
Dar, de obicei, obiectele trebuie să fie din aceeași clasă pentru a fi considerate egale. Prin urmare, dacă altceva decât un obiect al Person
clasei este transmis metodei noastre equals, atunci vom reveni întotdeauna false
. Cum poți verifica tipul unui obiect? Așa este, folosind instanceof
operatorul.
Iată cum arată noul nostru cod:
Cod | Descriere |
---|---|
|
Comparare referințe Este obiectul trecut null ? Dacă obiectul trecut nu este a Person |
4. Compararea a două Person
obiecte
Cu ce am ajuns? Dacă am ajuns la sfârșitul metodei, atunci avem o Person
referință la obiect care nu este null
. Deci îl convertim în a Person
și comparăm datele interne relevante ale ambelor obiecte. Și acesta este al patrulea scenariu al nostru .
Cod | Descriere |
---|---|
|
Comparare referințe Este obiectul trecut null ? Dacă obiectul transmis nu este un Person Typecasting |
Și cum compar două Person
obiecte? Sunt egali dacă au același nume ( name
) și vârstă ( age
). Codul final va arăta astfel:
Cod | Descriere |
---|---|
|
Comparare referințe Este obiectul trecut null ? Dacă obiectul transmis nu este un Person Typecasting |
Dar asta nu este tot.
În primul rând, câmpul de nume este un String
, așa că trebuie să comparați câmpul de nume apelând metoda equals
.
this.name.equals(person.name)
În al doilea rând, name
câmpul poate fi null
: în acest caz, nu îl puteți apela equals
. Aveți nevoie de o verificare suplimentară pentru null
:
this.name != null && this.name.equals(person.name)
Acestea fiind spuse, dacă câmpul nume este null
în ambele Person
obiecte, atunci numele sunt în continuare egale.
Codul pentru al patrulea scenariu ar putea arăta astfel:
|
Dacă vârstele nu sunt egale, imediat return false Dacă this.name este egal cu null , nu are rost să comparați folosind equals metoda. Aici, fie al doilea name câmp este egal cu null , fie nu este. Comparați cele două câmpuri de nume folosind equals metoda. |
5. hashCode()
metoda
Pe lângă equals
metodă, care are scopul de a efectua o comparație detaliată a tuturor câmpurilor ambelor obiecte, există o altă metodă care poate fi folosită pentru o comparație imprecisă, dar foarte rapidă: hashCode()
.
Imaginați-vă că sortați alfabetic o listă de mii de cuvinte și că trebuie să comparați în mod repetat perechi de cuvinte. Și cuvintele sunt lungi, constând din o mulțime de litere. În general, o astfel de comparație ar dura foarte mult timp.
Dar se poate accelera. Să presupunem că avem cuvinte care încep cu litere diferite - este imediat clar că sunt diferite. Dar dacă încep cu aceleași litere, atunci nu putem spune încă care va fi rezultatul: cuvintele se pot dovedi a fi egale sau diferite.
Metoda hashCode()
funcționează folosind un principiu similar. Dacă îl apelați pe un obiect, acesta returnează un număr - analog cu prima literă dintr-un cuvânt. Acest număr are următoarele proprietăți:
- Obiectele identice au întotdeauna același cod hash
- Diferite obiecte pot avea același hashcode, sau hashcode-urile lor pot fi diferite
- Dacă obiectele au coduri hash diferite, atunci obiectele sunt cu siguranță diferite
Pentru a face acest lucru și mai clar, să reformulam aceste proprietăți în termeni de cuvinte:
- Cuvintele identice au întotdeauna aceleași primele litere.
- Cuvintele diferite pot avea aceleași primele litere sau primele litere pot fi diferite
- Dacă cuvintele au primele litere diferite, atunci cuvintele sunt cu siguranță diferite
Ultima proprietate este folosită pentru a accelera compararea obiectelor:
Mai întâi, se calculează codurile hash ale celor două obiecte. Dacă aceste coduri hash sunt diferite, atunci obiectele sunt cu siguranță diferite și nu este nevoie să le comparați în continuare.
Dar dacă codurile hash sunt aceleași, atunci mai trebuie să comparăm obiectele folosind metoda equals.
6. Contracte în cod
Comportamentul descris mai sus trebuie implementat de toate clasele din Java. În timpul compilării, nu există nicio modalitate de a verifica dacă obiectele sunt comparate corect.
Programatorii Java au un acord universal că, dacă își scriu propria implementare a metodei equals() și, prin urmare, suprascriu implementarea standard (în clasă Object
), ei trebuie să scrie și propria lor implementare a hashCode()
metodei în așa fel încât regulile menționate mai sus să fie multumit.
Acest aranjament se numește contract .
Dacă implementați numai metoda equals()
sau numai hashCode()
metoda în clasa dvs., atunci vă aflați într-o încălcare gravă a contractului (ați încălcat acordul). Nu face asta.
Dacă alți programatori vă folosesc codul, este posibil să nu funcționeze corect. În plus, veți folosi cod care se bazează pe respectarea contractelor de mai sus.
Când căutați un element, toate colecțiile Java compară mai întâi codurile hash ale obiectelor și abia apoi efectuează o comparație folosind metoda equals
.
Asta înseamnă că dacă dai propriei clase o equals
metodă, dar nu scrii propria ta hashCode()
metodă sau o implementezi incorect, atunci colecțiile pot să nu funcționeze corect cu obiectele tale.
De exemplu, puteți adăuga un obiect la o listă și apoi îl căutați folosind metoda contains()
, dar colecția ar putea să nu vă găsească obiectul.
GO TO FULL VERSION