1. Objecten vergelijken in Java
In Java kunnen objecten zowel op referentie als op waarde worden vergeleken.
Referenties vergelijken
Als twee variabelen naar hetzelfde object in het geheugen wijzen, zijn de referenties die in deze variabelen zijn opgeslagen gelijk. Als je deze variabelen vergelijkt met de gelijkheidsoperator ( ==
), krijg je waar, en dat resultaat is logisch. Alles is hier eenvoudig.
Code | Console-uitvoer |
---|---|
|
|
Vergelijken op waarde
Maar u kunt vaak situaties tegenkomen waarin twee variabelen verwijzen naar twee afzonderlijke objecten die identiek zijn. Bijvoorbeeld twee verschillende strings-objecten die dezelfde tekst bevatten.
Gebruik de methode om te bepalen of verschillende objecten identiek zijn equals()
. Bijvoorbeeld:
Code | Console-uitvoer |
---|---|
|
|
De equals
methode is niet beperkt tot de String
klas. Elke klas heeft het.
Zelfs lessen die je zelf schrijft, en dit is waarom.
2. Object
klasse
Alle klassen in Java erven de Object
klasse. De makers van Java bedachten deze aanpak.
En als een klasse de Object
klasse overerft, krijgt deze alle methoden van de Object
klasse. En dit is een belangrijk gevolg van overerving.
Met andere woorden, elke klasse heeft de methoden van de Object
klasse, zelfs als hun code ze niet vermeldt.
Deze geërfde methoden omvatten methoden die verband houden met objectvergelijking. Dit zijn de methoden equals()
en hashCode()
.
Code | In werkelijkheid is dit wat we zullen hebben: |
---|---|
|
|
In het bovenstaande voorbeeld hebben we een eenvoudige Person
klasse gemaakt met naam- en leeftijdsparameters, maar geen enkele methode. Maar omdat alle klassen de Object
klasse erven, Person
heeft de klasse automatisch twee methoden:
Methode | Beschrijving |
---|---|
|
Vergelijkt het huidige object en het doorgegeven object |
|
Retourneert de hashcode van het huidige object |
Het blijkt dat absoluut elk object de equals
methode heeft en dat objecten van verschillende typen met elkaar kunnen worden vergeleken. Dergelijke code zal perfect compileren en werken.
Code | Console-uitvoer |
---|---|
|
|
|
|
3. equals()
methode
De equals()
methode, geërfd van de Object
klasse, implementeert het eenvoudigste algoritme voor het vergelijken van het huidige object met doorgegeven objecten: het vergelijkt alleen referenties naar de objecten.
U krijgt hetzelfde resultaat als u alleen Person
variabelen vergelijkt in plaats van de equals()
methode aan te roepen. Voorbeeld:
Code | Console-uitvoer |
---|---|
|
|
Wanneer de equals
methode wordt aangeroepen a
, vergelijkt deze eenvoudigweg de referentie die is opgeslagen in de a
variabele met de referentie die is opgeslagen in de b
variabele.
Vergelijken werkt echter anders voor de String
klas. Waarom?
Omdat de mensen die de String
klasse hebben gemaakt hun eigen implementatie van de equals()
methode hebben geschreven.
Implementatie van de equals()
methode
Laten we nu onze eigen implementatie van de methode equals in de Person
klas schrijven. We bekijken 4 hoofdgevallen.
equals
methode overschrijft, er is altijd een Object
object als argument nodig
Scenario 1 : hetzelfde object waarop de equals
methode wordt aangeroepen, wordt ook doorgegeven aan de equals
methode. Als de referenties van het huidige object en het doorgegeven object gelijk zijn, moet de methode retourneren true
. Een object is gelijk aan zichzelf.
In code ziet het er zo uit:
Code | Beschrijving |
---|---|
|
Referenties vergelijken |
Scenario 2 : null
wordt doorgegeven aan de equals
methode — we hebben niets om mee te vergelijken. Het object waarop de equals
methode wordt aangeroepen is beslist niet null, dus we moeten false
in dit geval terugkeren.
In code ziet het er zo uit:
Code | Beschrijving |
---|---|
|
Referenties vergelijken Is het doorgegeven object null ? |
Scenario 3 : een verwijzing naar een object dat geen a is, Person
wordt doorgegeven aan de equals
methode. Is het Person
object gelijk aan het niet- Person
object? Dat is een vraag voor de ontwikkelaar van de Person
klasse om te beslissen hoe hij of zij wil.
Maar meestal moeten objecten van dezelfde klasse zijn om als gelijk te worden beschouwd. Daarom, als er iets anders dan een object van de Person
klasse wordt doorgegeven aan onze equals-methode, dan zullen we altijd terugkeren false
. Hoe kun je het type van een object controleren? Dat klopt - door de instanceof
operator te gebruiken.
Zo ziet onze nieuwe code eruit:
Code | Beschrijving |
---|---|
|
Referenties vergelijken Is het doorgegeven object null ? Als het gepasseerde object geen a Person |
Person
4. Twee objecten vergelijken
Waar zijn we mee geëindigd? Als we het einde van de methode hebben bereikt, hebben we een Person
objectreferentie die dat niet is null
. Dus we converteren het naar a Person
en vergelijken de relevante interne gegevens van beide objecten. En dat is ons vierde scenario .
Code | Beschrijving |
---|---|
|
Referenties vergelijken Is het doorgegeven object null ? Als het gepasseerde object geen Person Typecasting is |
En hoe vergelijk je twee Person
objecten? Ze zijn gelijk als ze dezelfde naam ( name
) en leeftijd ( age
) hebben. De uiteindelijke code ziet er als volgt uit:
Code | Beschrijving |
---|---|
|
Referenties vergelijken Is het doorgegeven object null ? Als het gepasseerde object geen Person Typecasting is |
Maar dat is niet alles.
Ten eerste is het naamveld een String
, dus je moet het naamveld vergelijken door de equals
methode aan te roepen.
this.name.equals(person.name)
Ten tweede kan het name
veld zijn null
: in dat geval kunt u equals
er geen beroep op doen. U heeft een aanvullende controle nodig voor null
:
this.name != null && this.name.equals(person.name)
Dat gezegd hebbende, als het naamveld null
in beide Person
objecten staat, zijn de namen nog steeds gelijk.
De code voor het vierde scenario kan er als volgt uitzien:
|
Als de leeftijden niet gelijk zijn, heeft If gelijk aan , dan heeft het geen zin om met de methode te vergelijken. Hier is ofwel het tweede veld gelijk aan , ofwel niet. Vergelijk de twee naamvelden met behulp van de methode. return false this.name null equals name null equals |
5. hashCode()
methode
Naast de equals
methode, die bedoeld is om een gedetailleerde vergelijking van alle velden van beide objecten uit te voeren, is er nog een andere methode die kan worden gebruikt voor een onnauwkeurige maar zeer snelle vergelijking: hashCode()
.
Stel je voor dat je een lijst van duizenden woorden alfabetisch aan het sorteren bent en dat je herhaaldelijk woordparen moet vergelijken. En de woorden zijn lang, bestaande uit veel letters. Over het algemeen duurt zo'n vergelijking erg lang.
Maar het kan versneld worden. Stel dat we woorden hebben die met verschillende letters beginnen — het is meteen duidelijk dat ze verschillend zijn. Maar als ze met dezelfde letters beginnen, dan kunnen we nog niet zeggen wat het resultaat zal zijn: de woorden kunnen gelijk of verschillend blijken te zijn.
De hashCode()
methode werkt volgens een soortgelijk principe. Als je het op een object roept, geeft het een getal terug - analoog aan de eerste letter van een woord. Dit nummer heeft de volgende eigenschappen:
- Identieke objecten hebben altijd dezelfde hashcode
- Verschillende objecten kunnen dezelfde hashcode hebben, of hun hashcodes kunnen verschillend zijn
- Als objecten verschillende hashcodes hebben, dan zijn de objecten beslist verschillend
Om dit nog duidelijker te maken, laten we deze eigenschappen herformuleren in termen van woorden:
- Identieke woorden hebben altijd dezelfde beginletters.
- Verschillende woorden kunnen dezelfde eerste letters hebben, of hun eerste letters kunnen verschillend zijn
- Als woorden verschillende beginletters hebben, dan zijn de woorden beslist verschillend
De laatste eigenschap wordt gebruikt om de vergelijking van objecten te versnellen:
Eerst worden de hashcodes van de twee objecten berekend. Als deze hashcodes verschillend zijn, dan zijn de objecten beslist verschillend en is het niet nodig om ze verder te vergelijken.
Maar als de hashcodes hetzelfde zijn, dan moeten we de objecten nog steeds vergelijken met de equals-methode.
6. Contracten in code
Het hierboven beschreven gedrag moet door alle klassen in Java worden geïmplementeerd. Tijdens het compileren is er geen manier om te controleren of objecten correct worden vergeleken.
Java-programmeurs zijn het er algemeen over eens dat als ze hun eigen implementatie van de methode equals() schrijven en daarmee de standaardimplementatie (in de Object
klas) overschrijven, ze ook hun eigen implementatie van de hashCode()
methode zo moeten schrijven dat de bovengenoemde regels tevreden.
Deze regeling wordt een contract genoemd .
Als je alleen de equals()
of alleen de hashCode()
methode in je klas implementeert, ben je in grove overtreding van het contract (je hebt de overeenkomst verbroken). Doe dit niet.
Als andere programmeurs uw code gebruiken, werkt deze mogelijk niet correct. Bovendien gebruikt u code die afhankelijk is van naleving van de bovenstaande contracten.
Bij het zoeken naar een element vergelijken alle Java-collecties eerst de hashcodes van objecten en voeren pas daarna een vergelijking uit met behulp van de equals
methode.
Dat betekent dat als u uw eigen klasse een equals
methode geeft, maar u schrijft uw eigen methode niet hashCode()
of u implementeert deze verkeerd, collecties mogelijk niet correct werken met uw objecten.
U kunt bijvoorbeeld een object aan een lijst toevoegen en er vervolgens naar zoeken met behulp van de contains()
methode, maar de verzameling vindt uw object mogelijk niet.
GO TO FULL VERSION