1. Jämföra objekt i Java
I Java kan objekt jämföras både med referens och värde.
Jämför referenser
Om två variabler pekar på samma objekt i minnet är referenserna som lagras i dessa variabler lika. Om du jämför dessa variabler med hjälp av likhetsoperatorn ( ==), får du sanning, och det resultatet är vettigt. Allt är enkelt här.
| Koda | Konsolutgång |
|---|---|
|
|
Jämföra efter värde
Men du kan ofta stöta på situationer där två variabler refererar till två distinkta objekt som är identiska. Till exempel två olika strängobjekt som innehåller samma text.
För att avgöra om olika objekt är identiska, använd equals()metoden. Till exempel:
| Koda | Konsolutgång |
|---|---|
|
|
Metoden equalsär inte begränsad till Stringklassen. Varje klass har det.
Även klasser som du skriver på egen hand, och här är varför.
2. Objectklass
Alla klasser i Java ärver Objectklassen. Javas skapare kom på detta tillvägagångssätt.
Och om en klass ärver Objectklassen, får den alla klassens metoder Object. Och detta är en stor konsekvens av arv.
Med andra ord, varje klass har klassens metoder Object, även om deras kod inte nämner dem.
Dessa ärvda metoder inkluderar metoder relaterade till objektjämförelse. Dessa är equals()och hashCode()metoderna.
| Koda | I verkligheten, här är vad vi kommer att ha: |
|---|---|
|
|
I exemplet ovan skapade vi en enkel Personklass med namn- och åldersparametrar, men inte en enda metod. Men eftersom alla klasser ärver Objectklassen Personhar klassen automatiskt två metoder:
| Metod | Beskrivning |
|---|---|
|
Jämför det aktuella objektet och det skickade objektet |
|
Returnerar hashkoden för det aktuella objektet |
Det visar sig att absolut varje objekt har equalsmetoden, och objekt av olika typer kan jämföras med varandra. Sådan kod kommer att kompilera och fungera perfekt.
| Koda | Konsolutgång |
|---|---|
|
|
|
|
3. equals()metod
Metoden equals(), ärvd från Objectklassen, implementerar den enklaste algoritmen för att jämföra det aktuella objektet med skickade objekt: den jämför bara referenser till objekten.
Du får samma resultat om du bara jämför Personvariabler istället för att anropa equals()metoden. Exempel:
| Koda | Konsolutgång |
|---|---|
|
|
När equalsmetoden anropas ajämför den helt enkelt referensen lagrad i avariabeln med referensen lagrad i variabeln b.
Jämförelse fungerar dock annorlunda för Stringklassen. Varför?
Eftersom personerna som skapade Stringklassen skrev sin egen implementering av equals()metoden.
Implementering av equals()metoden
Låt oss nu skriva vår egen implementering av equals-metoden i Personklassen. Vi kommer att överväga 4 huvudfall.
equalsmetoden tar den alltid ett Objectobjekt som argument
Scenario 1 : samma objekt som equalsmetoden anropas på skickas också till equalsmetoden. Om referenserna för det aktuella objektet och det skickade objektet är lika, måste metoden returnera true. Ett föremål är lika med sig självt.
I koden kommer det se ut så här:
| Koda | Beskrivning |
|---|---|
|
Jämför referenser |
Scenario 2 : nullöverförs till equalsmetoden — vi har inget att jämföra med. Objektet som equalsmetoden anropas på är definitivt inte null, så vi måste återkomma falsei det här fallet.
I koden kommer det se ut så här:
| Koda | Beskrivning |
|---|---|
|
Jämför referenser Är det skickade objektet null? |
Scenario 3 : en referens till ett objekt som inte är ett Personskickas till equalsmetoden. Är Personobjektet lika med icke- Personobjektet? Det är en fråga för klassens utvecklare Personatt bestämma hur han eller hon vill.
Men vanligtvis måste objekt vara av samma klass för att anses lika. Därför, om något annat än ett objekt i Personklassen skickas till vår equals-metod, kommer vi alltid att returnera false. Hur kan du kontrollera typen av ett objekt? Det stämmer — genom att använda instanceofoperatören.
Så här ser vår nya kod ut:
| Koda | Beskrivning |
|---|---|
|
Jämför referenser Är det skickade objektet null? Om det passerade objektet inte är en Person |
4. Jämföra två Personobjekt
Vad slutade vi med? Om vi har nått slutet av metoden har vi en Personobjektreferens som inte är null. Så vi konverterar det till a Personoch jämför relevanta interna data för båda objekten. Och det är vårt fjärde scenario .
| Koda | Beskrivning |
|---|---|
|
Jämför referenser Är det skickade objektet null? Om det skickade objektet inte är en Person Typecasting |
Och hur jämför man två Personobjekt? De är lika om de har samma namn ( name) och ålder ( age). Den slutliga koden kommer att se ut så här:
| Koda | Beskrivning |
|---|---|
|
Jämför referenser Är det skickade objektet null? Om det skickade objektet inte är en Person Typecasting |
Men det är inte allt.
Först är namnfältet en String, så du måste jämföra namnfältet genom att anropa equalsmetoden.
this.name.equals(person.name)
För det andra namekan fältet vara null: i så fall kan du inte använda equalsdet. Du behöver en extra check för null:
this.name != null && this.name.equals(person.name)
Som sagt, om namnfältet finns nulli båda Personobjekten är namnen fortfarande lika.
Koden för det fjärde scenariot kan se ut så här:
|
Om åldrarna inte är lika, omedelbart return false If this.nameär lika med null, är det ingen idé att jämföra med equalsmetoden. Här är antingen det andra namefältet lika med null, eller så är det inte. Jämför de två namnfälten med equalsmetoden. |
5. hashCode()metod
Utöver equalsmetoden, som är avsedd att utföra en detaljerad jämförelse av alla fält för båda objekten, finns det en annan metod som kan användas för en oprecis men mycket snabb jämförelse: hashCode().
Föreställ dig att du sorterar alfabetiskt en lista med tusentals ord, och du måste upprepade gånger jämföra ordpar. Och orden är långa och består av massor av bokstäver. Generellt sett skulle en sådan jämförelse ta väldigt lång tid.
Men det går att påskynda. Anta att vi har ord som börjar med olika bokstäver — det är direkt tydligt att de är olika. Men om de börjar med samma bokstäver kan vi ännu inte säga vad resultatet blir: orden kan visa sig vara lika eller olika.
Metoden hashCode()fungerar enligt en liknande princip. Om du anropar det på ett objekt, returnerar det någon siffra - analogt med den första bokstaven i ett ord. Detta nummer har följande egenskaper:
- Identiska objekt har alltid samma hashkod
- Olika objekt kan ha samma hashkod, eller så kan deras hashkoder vara olika
- Om objekt har olika hashkoder, är objekten definitivt olika
För att göra detta ännu tydligare, låt oss omformulera dessa egenskaper i termer av ord:
- Identiska ord har alltid samma första bokstäver.
- Olika ord kan ha samma första bokstäver, eller deras första bokstäver kan vara olika
- Om ord har olika första bokstäver, så är orden definitivt olika
Den sista egenskapen används för att påskynda jämförelsen av objekt:
Först beräknas hashkoderna för de två objekten. Om dessa hashkoder är olika, är objekten definitivt olika, och det finns ingen anledning att jämföra dem ytterligare.
Men om hashkoderna är desamma måste vi fortfarande jämföra objekten med metoden equals.
6. Kontrakt i kod
Beteendet som beskrivs ovan måste implementeras av alla klasser i Java. Under kompileringen finns det inget sätt att kontrollera om objekt jämförs korrekt.
Java-programmerare har en universell överenskommelse om att om de skriver sin egen implementering av metoden equals() och därigenom åsidosätter standardimplementeringen (i klassen), så Objectmåste de också skriva sin egen implementering av hashCode()metoden på ett sådant sätt att de ovan nämnda reglerna är nöjd.
Detta arrangemang kallas ett kontrakt .
Om du implementerar endast metoden equals()eller bara hashCode()metoden i din klass, bryter du grovt mot avtalet (du har brutit mot avtalet). Gör inte det här.
Om andra programmerare använder din kod kanske den inte fungerar korrekt. Dessutom kommer du att använda kod som är beroende av att ovanstående avtal följs.
När du söker efter ett element jämför alla Java-samlingar först objektens hashkoder och utför först sedan en jämförelse med metoden equals.
Det betyder att om du ger din egen klass en equalsmetod men du inte skriver din egen hashCode()metod eller om du implementerar den felaktigt, kanske samlingar inte fungerar korrekt med dina objekt.
Du kan till exempel lägga till ett objekt i en lista och sedan söka efter det med metoden, contains()men samlingen kanske inte hittar ditt objekt.
GO TO FULL VERSION