1. Confronto di oggetti in Java
In Java, gli oggetti possono essere confrontati sia per riferimento che per valore.
Referenze a confronto
Se due variabili puntano allo stesso oggetto in memoria, i riferimenti memorizzati in queste variabili sono uguali. Se si confrontano queste variabili utilizzando l'operatore di uguaglianza ( ==
), si ottiene true e il risultato ha senso. Tutto è semplice qui.
Codice | Uscita console |
---|---|
|
|
Confronto per valore
Ma spesso puoi incontrare situazioni in cui due variabili si riferiscono a due oggetti distinti che sono identici. Ad esempio, due diversi oggetti stringhe che contengono lo stesso testo.
Per determinare se diversi oggetti sono identici, utilizzare il equals()
metodo. Per esempio:
Codice | Uscita console |
---|---|
|
|
Il equals
metodo non è limitato alla String
classe. Ogni classe ce l'ha.
Anche lezioni che scrivi da solo, ed ecco perché.
2. Object
classe
Tutte le classi in Java ereditano la Object
classe. I creatori di Java hanno escogitato questo approccio.
E se una classe eredita la Object
classe, ottiene tutti i metodi della Object
classe. E questa è una conseguenza importante dell'ereditarietà.
In altre parole, ogni classe ha i metodi della Object
classe, anche se il loro codice non li menziona.
Questi metodi ereditati includono metodi relativi al confronto di oggetti. Questi sono i metodi equals()
e hashCode()
.
Codice | In realtà, ecco cosa avremo: |
---|---|
|
|
Nell'esempio sopra, abbiamo creato una Person
classe semplice con parametri nome ed età, ma non un singolo metodo. Ma poiché tutte le classi ereditano la Object
classe, la Person
classe ha automaticamente due metodi:
Metodo | Descrizione |
---|---|
|
Confronta l'oggetto corrente e l'oggetto passato |
|
Restituisce il codice hash dell'oggetto corrente |
Si scopre che assolutamente ogni oggetto ha il equals
metodo e oggetti di tipi diversi possono essere confrontati tra loro. Tale codice verrà compilato e funzionerà perfettamente.
Codice | Uscita console |
---|---|
|
|
|
|
3. equals()
metodo
Il equals()
metodo, ereditato dalla Object
classe, implementa l'algoritmo più semplice per confrontare l'oggetto corrente con gli oggetti passati: confronta solo i riferimenti agli oggetti.
Ottieni lo stesso risultato se confronti solo Person
le variabili invece di chiamare il equals()
metodo. Esempio:
Codice | Uscita console |
---|---|
|
|
Quando il equals
metodo viene chiamato a
, confronta semplicemente il riferimento memorizzato nella a
variabile con il riferimento memorizzato nella b
variabile.
Tuttavia, il confronto funziona in modo diverso per la String
classe. Perché?
Perché le persone che hanno creato la String
classe hanno scritto la propria implementazione del equals()
metodo.
Implementazione del equals()
metodo
Ora scriviamo la nostra implementazione del metodo equals nella Person
classe. Prenderemo in considerazione 4 casi principali.
equals
metodo, prende sempre un Object
oggetto come argomento
Scenario 1 : lo stesso oggetto su cui equals
viene chiamato il metodo viene passato anche al equals
metodo. Se i riferimenti dell'oggetto corrente e dell'oggetto passato sono uguali, il metodo deve restituire true
. Un oggetto è uguale a se stesso.
Nel codice sarà simile a questo:
Codice | Descrizione |
---|---|
|
Confronta i riferimenti |
Scenario 2 : null
viene passato al equals
metodo: non abbiamo nulla con cui confrontarci. L'oggetto su cui viene chiamato il metodo non è sicuramente nullo, quindi in questo caso equals
dobbiamo tornare .false
Nel codice sarà simile a questo:
Codice | Descrizione |
---|---|
|
Confronta i riferimenti È l'oggetto passato null ? |
Scenario 3 : un riferimento a un oggetto che non è a Person
viene passato al equals
metodo. L'oggetto è Person
uguale al non Person
oggetto? Questa è una domanda che lo sviluppatore della Person
classe deve decidere come vuole.
Ma di solito gli oggetti devono essere della stessa classe per essere considerati uguali. Pertanto, se al nostro metodo equals viene passato qualcosa di diverso da un oggetto della Person
classe, restituiremo sempre false
. Come puoi controllare il tipo di un oggetto? Esatto, utilizzando l' instanceof
operatore.
Ecco come appare il nostro nuovo codice:
Codice | Descrizione |
---|---|
|
Confronta i riferimenti È l'oggetto passato null ? Se l'oggetto passato non è a Person |
4. Confrontare due Person
oggetti
Con cosa siamo finiti? Se abbiamo raggiunto la fine del metodo, allora abbiamo un Person
riferimento all'oggetto che non è null
. Quindi lo convertiamo in a Person
e confrontiamo i dati interni rilevanti di entrambi gli oggetti. E questo è il nostro quarto scenario .
Codice | Descrizione |
---|---|
|
Confronta i riferimenti È l'oggetto passato null ? Se l'oggetto passato non è un Person Typecasting |
E come si confrontano due Person
oggetti? Sono uguali se hanno lo stesso nome ( name
) ed età ( age
). Il codice finale sarà simile a questo:
Codice | Descrizione |
---|---|
|
Confronta i riferimenti È l'oggetto passato null ? Se l'oggetto passato non è un Person Typecasting |
Ma non è tutto.
Innanzitutto, il campo del nome è un String
, quindi è necessario confrontare il campo del nome chiamando il equals
metodo.
this.name.equals(person.name)
In secondo luogo, il name
campo potrebbe essere null
: in tal caso, non puoi richiamarlo equals
. Hai bisogno di un assegno aggiuntivo per null
:
this.name != null && this.name.equals(person.name)
Detto questo, se il campo del nome si trova null
in entrambi Person
gli oggetti, i nomi sono comunque uguali.
Il codice per il quarto scenario potrebbe essere simile al seguente:
|
Se le età non sono uguali, immediatamente return false If this.name è uguale a null , non ha senso confrontare usando il equals metodo. Qui o il secondo name campo è uguale a null o non lo è. Confronta i due campi del nome utilizzando il equals metodo. |
5. hashCode()
metodo
Oltre al equals
metodo, che ha lo scopo di eseguire un confronto dettagliato di tutti i campi di entrambi gli oggetti, esiste un altro metodo che può essere utilizzato per un confronto impreciso ma molto rapido: hashCode()
.
Immagina di ordinare alfabeticamente un elenco di migliaia di parole e di dover confrontare ripetutamente coppie di parole. E le parole sono lunghe, composte da molte lettere. In generale, un simile confronto richiederebbe molto tempo.
Ma può essere accelerato. Supponiamo di avere parole che iniziano con lettere diverse: è subito chiaro che sono diverse. Ma se iniziano con le stesse lettere, allora non possiamo ancora dire quale sarà il risultato: le parole potrebbero risultare uguali o diverse.
Il hashCode()
metodo funziona utilizzando un principio simile. Se lo chiami su un oggetto, restituisce un numero, analogo alla prima lettera di una parola. Questo numero ha le seguenti proprietà:
- Oggetti identici hanno sempre lo stesso hashcode
- Oggetti diversi possono avere lo stesso codice hash o i loro codici hash possono essere diversi
- Se gli oggetti hanno codici hash diversi, allora gli oggetti sono decisamente diversi
Per renderlo ancora più chiaro, riformuliamo queste proprietà in termini di parole:
- Le parole identiche hanno sempre le stesse prime lettere.
- Parole diverse possono avere le stesse prime lettere o le loro prime lettere possono essere diverse
- Se le parole hanno lettere iniziali diverse, allora le parole sono decisamente diverse
L'ultima proprietà viene utilizzata per accelerare il confronto degli oggetti:
Innanzitutto, vengono calcolati gli hashcode dei due oggetti. Se questi codici hash sono diversi, gli oggetti sono decisamente diversi e non è necessario confrontarli ulteriormente.
Ma se gli hashcode sono gli stessi, dobbiamo comunque confrontare gli oggetti usando il metodo equals.
6. Contratti in codice
Il comportamento sopra descritto deve essere implementato da tutte le classi in Java. Durante la compilazione, non è possibile verificare se gli oggetti vengono confrontati correttamente.
I programmatori Java hanno un accordo universale sul fatto che se scrivono la propria implementazione del metodo equals() e quindi sovrascrivono l'implementazione standard (nella Object
classe), devono anche scrivere la propria implementazione del hashCode()
metodo in modo tale che le suddette regole siano soddisfatto.
Questa disposizione è chiamata contratto .
Se implementi solo il equals()
o solo il hashCode()
metodo nella tua classe, allora sei in grave violazione del contratto (hai rotto l'accordo). Non farlo.
Se altri programmatori utilizzano il tuo codice, potrebbe non funzionare correttamente. Inoltre, utilizzerai un codice che si basa sull'adesione ai contratti di cui sopra.
Durante la ricerca di un elemento, tutte le raccolte Java confrontano prima i codici hash degli oggetti e solo successivamente eseguono un confronto utilizzando il equals
metodo.
Ciò significa che se dai alla tua classe un equals
metodo ma non scrivi il tuo hashCode()
metodo o lo implementi in modo errato, le raccolte potrebbero non funzionare correttamente con i tuoi oggetti.
Ad esempio, potresti aggiungere un oggetto a un elenco e quindi cercarlo utilizzando il contains()
metodo, ma la raccolta potrebbe non trovare il tuo oggetto.
GO TO FULL VERSION