1. Sammenligne objekter i Java
I Java kan objekter sammenlignes både etter referanse og etter verdi.
Sammenligning av referanser
Hvis to variabler peker på det samme objektet i minnet, er referansene som er lagret i disse variablene like. Hvis du sammenligner disse variablene ved å bruke likhetsoperatoren ( ==
), får du sannhet, og det resultatet gir mening. Alt er enkelt her.
Kode | Konsollutgang |
---|---|
|
|
Sammenligning etter verdi
Men du kan ofte støte på situasjoner der to variabler refererer til to distinkte objekter som er identiske. For eksempel to forskjellige strengobjekter som inneholder samme tekst.
For å finne ut om ulike objekter er identiske, bruk equals()
metoden. For eksempel:
Kode | Konsollutgang |
---|---|
|
|
Metoden equals
er ikke begrenset til String
klassen. Hver klasse har det.
Til og med klasser som du skriver på egen hånd, og her er hvorfor.
2. Object
klasse
Alle klasser i Java arver Object
klassen. Javas skapere kom opp med denne tilnærmingen.
Og hvis en klasse arver Object
klassen, får den alle metodene til klassen Object
. Og dette er en stor konsekvens av arv.
Med andre ord, hver klasse har metodene til Object
klassen, selv om koden deres ikke nevner dem.
Disse nedarvede metodene inkluderer metoder relatert til objektsammenligning. Dette er equals()
og hashCode()
metodene.
Kode | I virkeligheten, her er det vi har: |
---|---|
|
|
I eksemplet ovenfor opprettet vi en enkel Person
klasse med navn og aldersparametere, men ikke en enkelt metode. Men fordi alle klasser arver Object
klassen, Person
har klassen automatisk to metoder:
Metode | Beskrivelse |
---|---|
|
Sammenligner gjeldende objekt og bestått objekt |
|
Returnerer hashkoden til gjeldende objekt |
Det viser seg at absolutt alle objekter har equals
metoden, og objekter av forskjellige typer kan sammenlignes med hverandre. Slik kode vil kompilere og fungere perfekt.
Kode | Konsollutgang |
---|---|
|
|
|
|
3. equals()
metode
Metoden equals()
, arvet fra Object
klassen, implementerer den enkleste algoritmen for å sammenligne gjeldende objekt med beståtte objekter: den sammenligner bare referanser til objektene.
Du får samme resultat hvis du bare sammenligner Person
variabler i stedet for å kalle equals()
metoden. Eksempel:
Kode | Konsollutgang |
---|---|
|
|
Når equals
metoden kalles på a
, sammenligner den ganske enkelt referansen som er lagret i a
variabelen med referansen som er lagret i b
variabelen.
Sammenligning fungerer imidlertid annerledes for String
klassen. Hvorfor?
Fordi folkene som opprettet String
klassen skrev sin egen implementering av equals()
metoden.
Implementering av equals()
metoden
La oss nå skrive vår egen implementering av likhetsmetoden i Person
klassen. Vi skal vurdere 4 hovedsaker.
equals
metoden, tar den alltid et Object
objekt som argument
Scenario 1 : det samme objektet som metoden equals
kalles på, sendes også til equals
metoden. Hvis referansene til det gjeldende objektet og det beståtte objektet er like, må metoden returnere true
. Et objekt er lik seg selv.
I koden vil det se slik ut:
Kode | Beskrivelse |
---|---|
|
Sammenlign referanser |
Scenario 2 : null
overføres til equals
metoden — vi har ingenting å sammenligne med. Objektet som equals
metoden kalles på er definitivt ikke null, så vi må gå tilbake false
i dette tilfellet.
I koden vil det se slik ut:
Kode | Beskrivelse |
---|---|
|
Sammenlign referanser Er det beståtte objektet null ? |
Scenario 3 : en referanse til et objekt som ikke er en Person
blir sendt til equals
metoden. Er Person
objektet lik ikke- Person
objektet? Det er et spørsmål for utvikleren av klassen Person
å bestemme hvordan han eller hun vil.
Men vanligvis må objekter være av samme klasse for å regnes som like. Derfor, hvis noe annet enn et objekt i Person
klassen sendes til vår likhetsmetode, vil vi alltid returnere false
. Hvordan kan du sjekke typen av et objekt? Det stemmer – ved å bruke instanceof
operatøren.
Slik ser den nye koden vår ut:
Kode | Beskrivelse |
---|---|
|
Sammenlign referanser Er det beståtte objektet null ? Hvis det passerte objektet ikke er en Person |
4. Sammenligning av to Person
objekter
Hva endte vi opp med? Hvis vi har kommet til slutten av metoden, så har vi en Person
objektreferanse som ikke er null
. Så vi konverterer det til a Person
og sammenligner de relevante interne dataene til begge objektene. Og det er vårt fjerde scenario .
Kode | Beskrivelse |
---|---|
|
Sammenlign referanser Er det beståtte objektet null ? Hvis det beståtte objektet ikke er en Person Typecasting |
Og hvordan sammenligner du to Person
objekter? De er like hvis de har samme navn ( name
) og alder ( age
). Den endelige koden vil se slik ut:
Kode | Beskrivelse |
---|---|
|
Sammenlign referanser Er det beståtte objektet null ? Hvis det beståtte objektet ikke er en Person Typecasting |
Men det er ikke alt.
Først er navnefeltet en String
, så du må sammenligne navnefeltet ved å kalle metoden equals
.
this.name.equals(person.name)
For det andre name
kan feltet være null
: i så fall kan du ikke bruke equals
det. Du trenger en ekstra sjekk for null
:
this.name != null && this.name.equals(person.name)
Når det er sagt, hvis navnefeltet er null
i begge Person
objektene, er navnene fortsatt like.
Koden for det fjerde scenariet kan se slik ut:
|
Hvis alderen ikke er like, umiddelbart return false If this.name er lik null , er det ingen vits i å sammenligne med metoden equals . Her er enten det andre name feltet lik null , eller så er det ikke. Sammenlign de to navnefeltene ved å bruke equals metoden. |
5. hashCode()
metode
I tillegg til equals
metoden, som er ment å utføre en detaljert sammenligning av alle feltene til begge objektene, er det en annen metode som kan brukes for en upresis, men veldig rask sammenligning: hashCode()
.
Tenk deg at du sorterer alfabetisk en liste med tusenvis av ord, og du må gjentatte ganger sammenligne ordpar. Og ordene er lange, bestående av mange bokstaver. Generelt sett vil en slik sammenligning ta svært lang tid.
Men det kan akselereres. Anta at vi har ord som begynner med forskjellige bokstaver - det er umiddelbart klart at de er forskjellige. Men hvis de begynner med de samme bokstavene, kan vi ennå ikke si hva resultatet blir: ordene kan vise seg å være like eller forskjellige.
Metoden hashCode()
fungerer etter et lignende prinsipp. Hvis du kaller det på et objekt, returnerer det et tall - analogt med den første bokstaven i et ord. Dette nummeret har følgende egenskaper:
- Identiske objekter har alltid samme hashkode
- Ulike objekter kan ha samme hashkode, eller hashkodene deres kan være forskjellige
- Hvis objekter har forskjellige hashkoder, er objektene definitivt forskjellige
For å gjøre dette enda mer tydelig, la oss omforme disse egenskapene i form av ord:
- Identiske ord har alltid de samme første bokstavene.
- Ulike ord kan ha de samme første bokstavene, eller de første bokstavene kan være forskjellige
- Hvis ord har forskjellige forbokstaver, er ordene definitivt forskjellige
Den siste egenskapen brukes til å akselerere sammenligning av objekter:
Først beregnes hashkodene til de to objektene. Hvis disse hashkodene er forskjellige, er objektene definitivt forskjellige, og det er ikke nødvendig å sammenligne dem ytterligere.
Men hvis hashkodene er de samme, må vi fortsatt sammenligne objektene ved å bruke likhetsmetoden.
6. Kontrakter i kode
Oppførselen beskrevet ovenfor må implementeres av alle klasser i Java. Under kompilering er det ingen måte å sjekke om objekter sammenlignes riktig.
Java-programmerere har en universell avtale om at hvis de skriver sin egen implementering av equals()-metoden og dermed overstyrer standardimplementeringen (i klassen Object
), må de også skrive sin egen implementering av hashCode()
metoden på en slik måte at de nevnte reglene er fornøyd.
Denne ordningen kalles en kontrakt .
Hvis du implementerer bare metoden equals()
eller bare hashCode()
metoden i klassen din, bryter du grovt kontrakten (du har brutt avtalen). Ikke gjør dette.
Hvis andre programmerere bruker koden din, kan det hende at den ikke fungerer som den skal. Dessuten vil du bruke kode som er avhengig av overholdelse av kontraktene ovenfor.
Når du søker etter et element, sammenligner alle Java-samlinger først hashkodene til objekter, og først deretter utfører de en sammenligning ved hjelp av metoden equals
.
Det betyr at hvis du gir din egen klasse en equals
metode, men du ikke skriver din egen hashCode()
metode, eller du implementerer den feil, kan det hende at samlinger ikke fungerer riktig med objektene dine.
Du kan for eksempel legge til et objekt i en liste og deretter søke etter det ved hjelp av metoden contains()
, men samlingen finner kanskje ikke objektet ditt.
GO TO FULL VERSION