1. Sammenligning af objekter i Java
I Java kan objekter sammenlignes både efter reference og efter værdi.
Sammenligning af referencer
Hvis to variabler peger på det samme objekt i hukommelsen, så er referencerne gemt i disse variable ens. Hvis du sammenligner disse variable ved hjælp af lighedsoperatoren ( ==
), får du sandhed, og det resultat giver mening. Alt er enkelt her.
Kode | Konsoludgang |
---|---|
|
|
Sammenligning efter værdi
Men du kan ofte støde på situationer, hvor to variable refererer til to forskellige objekter, der er identiske. For eksempel to forskellige strengobjekter, der indeholder den samme tekst.
For at afgøre, om forskellige objekter er identiske, skal du bruge equals()
metoden. For eksempel:
Kode | Konsoludgang |
---|---|
|
|
Metoden equals
er ikke begrænset til String
klassen. Hver klasse har det.
Selv klasser, som du skriver på egen hånd, og her er hvorfor.
2. Object
klasse
Alle klasser i Java arver Object
klassen. Javas skabere fandt på denne tilgang.
Og hvis en klasse arver Object
klassen, får den alle klassens metoder Object
. Og det er en stor konsekvens af arv.
Med andre ord, hver klasse har klassens metoder Object
, selvom deres kode ikke nævner dem.
Disse nedarvede metoder omfatter metoder relateret til objektsammenligning. Disse er equals()
og hashCode()
metoderne.
Kode | I virkeligheden er det her, vi har: |
---|---|
|
|
I eksemplet ovenfor oprettede vi en simpel Person
klasse med navn og aldersparametre, men ikke en enkelt metode. Men fordi alle klasser arver Object
klassen, Person
har klassen automatisk to metoder:
Metode | Beskrivelse |
---|---|
|
Sammenligner det aktuelle objekt og det beståede objekt |
|
Returnerer hashkoden for det aktuelle objekt |
Det viser sig, at absolut alle objekter har equals
metoden, og objekter af forskellige typer kan sammenlignes med hinanden. En sådan kode vil kompilere og fungere perfekt.
Kode | Konsoludgang |
---|---|
|
|
|
|
3. equals()
metode
Metoden equals()
, der er arvet fra Object
klassen, implementerer den enkleste algoritme til at sammenligne det aktuelle objekt med beståede objekter: den sammenligner blot referencer til objekterne.
Du får det samme resultat, hvis du bare sammenligner Person
variable i stedet for at kalde equals()
metoden. Eksempel:
Kode | Konsoludgang |
---|---|
|
|
Når equals
metoden kaldes på a
, sammenligner den blot referencen gemt i a
variablen med referencen gemt i b
variablen.
Sammenligning fungerer dog anderledes for String
klassen. Hvorfor?
Fordi folkene, der skabte String
klassen, skrev deres egen implementering af equals()
metoden.
Implementering af equals()
metoden
Lad os nu skrive vores egen implementering af equals-metoden i Person
klassen. Vi vil overveje 4 hovedsager.
equals
metoden, tager den altid et Object
objekt som et argument
Scenarie 1 : det samme objekt, som metoden equals
kaldes på, videregives også til equals
metoden. Hvis referencerne for det aktuelle objekt og det beståede objekt er ens, skal metoden returnere true
. Et objekt er lig med sig selv.
I koden vil det se sådan ud:
Kode | Beskrivelse |
---|---|
|
Sammenlign referencer |
Scenarie 2 : null
videregives til equals
metoden - vi har intet at sammenligne med. Objektet, som equals
metoden kaldes på, er bestemt ikke null, så vi skal vende tilbage false
i dette tilfælde.
I koden vil det se sådan ud:
Kode | Beskrivelse |
---|---|
|
Sammenlign referencer Er det beståede objekt null ? |
Scenarie 3 : en reference til et objekt, der ikke er en, Person
videregives til equals
metoden. Er Person
objektet lig med ikke- Person
objektet? Det er et spørgsmål for udvikleren af klassen Person
at beslutte, hvordan han eller hun vil.
Men normalt skal objekter være af samme klasse for at blive betragtet som lige. Derfor, hvis noget andet end et objekt i Person
klassen overføres til vores equals-metode, vil vi altid returnere false
. Hvordan kan du kontrollere typen af et objekt? Det er rigtigt - ved at bruge instanceof
operatøren.
Sådan ser vores nye kode ud:
Kode | Beskrivelse |
---|---|
|
Sammenlign referencer Er det beståede objekt null ? Hvis det passerede objekt ikke er en Person |
4. Sammenligning af to Person
objekter
Hvad endte vi med? Hvis vi er nået til slutningen af metoden, så har vi en Person
objektreference, der ikke er null
. Så vi konverterer det til a Person
og sammenligner de relevante interne data for begge objekter. Og det er vores fjerde scenarie .
Kode | Beskrivelse |
---|---|
|
Sammenlign referencer Er det beståede objekt null ? Hvis det beståede objekt ikke er en Person Typecasting |
Og hvordan sammenligner man to Person
objekter? De er ens, hvis de har samme navn ( name
) og alder ( age
). Den endelige kode vil se sådan ud:
Kode | Beskrivelse |
---|---|
|
Sammenlign referencer Er det beståede objekt null ? Hvis det beståede objekt ikke er en Person Typecasting |
Men det er ikke alt.
Først er navnefeltet et String
, så du skal sammenligne navnefeltet ved at kalde equals
metoden.
this.name.equals(person.name)
For det andet name
kan feltet være null
: i så fald kan du ikke kalde equals
på det. Du skal bruge en ekstra check til null
:
this.name != null && this.name.equals(person.name)
Når det er sagt, hvis navnefeltet er null
i begge Person
objekter, så er navnene stadig ens.
Koden til det fjerde scenarie kan se sådan ud:
|
Hvis aldre ikke er ens, umiddelbart return false If this.name er lig med null , er der ingen mening i at sammenligne ved hjælp af equals metoden. Her er enten det andet name felt lig med null , eller også er det ikke. Sammenlign de to navnefelter ved hjælp af equals metoden. |
5. hashCode()
metode
Ud over equals
metoden, som er beregnet til at udføre en detaljeret sammenligning af alle felterne for begge objekter, er der en anden metode, der kan bruges til en upræcis, men meget hurtig sammenligning: hashCode()
.
Forestil dig, at du alfabetisk sorterer en liste med tusindvis af ord, og du skal gentagne gange sammenligne ordpar. Og ordene er lange og består af masser af bogstaver. Generelt vil en sådan sammenligning tage meget lang tid.
Men det kan accelereres. Antag, at vi har ord, der begynder med forskellige bogstaver - det er umiddelbart klart, at de er forskellige. Men hvis de begynder med de samme bogstaver, så kan vi endnu ikke sige, hvad resultatet bliver: ordene kan vise sig at være ens eller forskellige.
Metoden hashCode()
fungerer efter et lignende princip. Hvis du kalder det på et objekt, returnerer det et eller andet tal - analogt med det første bogstav i et ord. Dette nummer har følgende egenskaber:
- Identiske objekter har altid den samme hashkode
- Forskellige objekter kan have den samme hashkode, eller deres hashkoder kan være forskellige
- Hvis objekter har forskellige hashkoder, så er objekterne helt sikkert forskellige
For at gøre dette endnu mere klart, lad os omformulere disse egenskaber i form af ord:
- Identiske ord har altid de samme første bogstaver.
- Forskellige ord kan have de samme første bogstaver, eller deres første bogstaver kan være forskellige
- Hvis ord har forskellige første bogstaver, så er ordene helt sikkert forskellige
Den sidste egenskab bruges til at fremskynde sammenligning af objekter:
Først beregnes hashkoderne for de to objekter. Hvis disse hashkoder er forskellige, så er objekterne bestemt forskellige, og der er ingen grund til at sammenligne dem yderligere.
Men hvis hashkoderne er de samme, så skal vi stadig sammenligne objekterne ved hjælp af equals-metoden.
6. Kontrakter i kode
Den ovenfor beskrevne adfærd skal implementeres af alle klasser i Java. Under kompilering er der ingen måde at kontrollere, om objekter sammenlignes korrekt.
Java-programmører har en universel aftale om, at hvis de skriver deres egen implementering af equals()-metoden og derved tilsidesætter standardimplementeringen (i klassen Object
), skal de også skrive deres egen implementering af metoden hashCode()
på en sådan måde, at de førnævnte regler er tilfreds.
Denne ordning kaldes en kontrakt .
Hvis du kun implementerer equals()
eller kun hashCode()
metoden i din klasse, er du i grov overtrædelse af kontrakten (du har brudt aftalen). Gør ikke dette.
Hvis andre programmører bruger din kode, fungerer den muligvis ikke korrekt. Hvad mere er, vil du bruge kode, der er afhængig af overholdelse af ovenstående kontrakter.
Når du søger efter et element, sammenligner alle Java-samlinger først objekternes hashkoder og udfører først derefter en sammenligning ved hjælp af metoden equals
.
Det betyder, at hvis du giver din egen klasse en equals
metode, men du ikke skriver din egen hashCode()
metode, eller du implementerer den forkert, så fungerer samlinger muligvis ikke korrekt med dine objekter.
For eksempel kan du tilføje et objekt til en liste og derefter søge efter det ved hjælp af metoden contains()
, men samlingen finder muligvis ikke dit objekt.
GO TO FULL VERSION