Java è un linguaggio di programmazione ad oggetti. Questo implica che tutto quello che si rappresenta è un oggetto.
Una delle operazioni più comuni che si possano fare è confrontare 2 oggetti per stabilire se essi siano uguali o meno.
Quando facciamo ciò dobbiamo specificare che tipo di uguaglianza vogliamo verificare:
- Uguaglianza superficiale: verifica se 2 riferimenti ad oggetto sono uguali (puntano allo stesso oggetto)
- Uguaglianza profonda: verifica se gli oggetti, con le informazioni in essi contenute, sono uguali
Facciamo un semplicissimo esempio:
Implementiamo una classe di prova con 2 variabili d'istanza di tipo double.
public class ProvaUguaglianza {
// Variabili d'istanza
public double a;
public double b;
// Costruttore
public ProvaUguaglianza(double a, double b) {
this.a=a;
this.b=b;
}
}
Ora (ad esempio nel metodo main) creiamo 2 oggetti di tipo ProvaUguaglianza
ProvaUguaglianza p1 = new ProvaUguaglianza(10.5, 4.8);
ProvaUguaglianza p2 = new ProvaUguaglianza(10.5, 4.8);
Come possiamo notare, ho creato 2 oggetti differenti (p1 e p2) utilizzando il costruttore della classe ProvaUguaglianza.
Ho passato gli stessi identici parametri per assegnare un valore alle 2 variabili d'istanza.
Possiamo concludere dicendo che:
- p1 e p2 sono 2 oggetti differenti ---> Non sono uguali superficialmente
- p1 e p2 hanno informazioni identiche ----> Sono uguali profondamente
Uguaglianza superficiale
Per verificare l'uguaglianza superficiale di 2 oggetti utilizziamo l'operatore '=='
Se consideriamo il codice precedente e scriviamo...
if( p1 == p2 ){
System.out.println("Uguali");
}
else{
System.out.println("Diversi");
}
...viene stampato a video "Diversi".
Infatti, essendo p1 e p2 due oggetti differenti, non hanno valori di riferimento uguali. Per questo motivo p1 == p2 sarà sempre false;
Uguaglianza profonda
Per verificare l'uguaglianza profonda tra 2 oggetti si utilizza il metodo public boolean equals(Object)
Questo metodo è definito nella classe Object e per questo motivo, per poterlo utilizzare, deve essere ridefinito (overriding) altrimenti si comporterà esattamente come l'operatore '=='
Ora effettuiamo l'overriding di equals per verificare l'uguaglianza profonda della classe ProvaUguaglianza di prima
public class ProvaUguaglianza {
....
....
....
// Overriding di equals
public boolean equals(Object o) {
if(o != null & getClass().equals(o.getClass()) ) {
ProvaUguaglianza temp = (ProvaUguaglianza)o;
return (temp.a == this.a) & (temp.b == this.b);
}
else return false;
}
}
Andiamo a spiegare quanto fatto riga per riga:
- public boolean equals(Object o) - La funzione deve avere la stessa segnatura del metodo di Object. Infatti stiamo effettuando l'overriding dello stesso.
- if(o != null .. - Dobbiamo assicurarci che l'oggetto passato come argomento ad equals non abbia valore null. Se così fosse gli oggetti sarebbero banalmente differenti. Questo deve essere necessarimente il primo controllo da effettuare.
- ... & getClass().equals(o.getClass()) - Verifichiamo che i due oggetti siano istanza della stessa classe (risulta inutile confrontare l'oggetto 'Casa' con l'oggetto 'Albero', sono banalmente differenti)
- ProvaUguaglianza temp = (ProvaUguaglianza)o; - Se la condizione di if viene verificata, effettuiamo il cast per poter accedere ai campi della classe ProvaUguaglianza
- return (temp.a == this.a) & (temp.b == this.b); - Andiamo a verificare che i singoli campi siano effettivamente uguali tra loro. (Abbiamo utilizzando l'uguaglianza superficiale perchè double è un tipo primitivo di Java)
- else return false - Se la condizione di if non è verificata vuol dire che l'oggetto passato come paramentro ha valore null oppure appartiene ad una classe differente
hashCode()
Ogni volta che effettuiamo l'overriding di equals() dobbiamo assicurarci che il metodo hashCode() sia consistente con esso. Infatti se due oggetti sono uguali secondo equals() allora devono avere lo stesso codice di hash secondo hashCode(). Non necessariamente vale il contrario.