Confronti, equals

Transcript

Confronti, equals
Confronti, equals
Operatori Relazionali, confronti
Confronti fra Oggetti, ridefinizione di equals
Laboratorio di Programmazione - Luca Tesei
1
Operatori relazionali
●
●
All’interno delle parentesi tonde della
condizione dell’if è possibile, come abbiamo
visto, inserire il confronto tra due valori poiché
questa espressione ha un valore di tipo
boolean (true o false)
Vediamo, nella tabella seguente, tutti gli
operatori relazionali che possiamo usare:
Laboratorio di Programmazione - Luca Tesei
2
Operatori Relazionali
Operatore Java Notazione matematica
Descrizione
>
>
Maggiore
>=

Maggiore o uguale
<
<
Minore
<=

Minore o uguale
==
=
Uguale
!=

Diverso
Laboratorio di Programmazione - Luca Tesei
3
Errore comune: = invece di ==
I programmatori ancora inesperti spesso
confondono l’uso di = con ==
● In particolare un errore comune è quello di
inserire in un confronto l’operatore = invece che
==
• if (a=5) b++; // Errore di compilazione
● L’espressione a=5, oltre ad essere un
assegnamento e non un confronto, ha un
valore di tipo int
●
Laboratorio di Programmazione - Luca Tesei
4
Confronti di valori in virgola
mobile
●
●
●
●
Gli operatori == o != non hanno molto senso
applicati a valori in virgola mobile
Un errore tipico è quello di cercare di controllare
se un valore double (o float) sia uguale a
0.0
È molto improbabile che un double risultante
da un calcolo sia esattamente zero
Potrebbe essere invece un valore prossimo allo
zero
Laboratorio di Programmazione - Luca Tesei
5
Confronti di valori in virgola
mobile
●
Prendiamo ad esempio questo semplice programma:
double r = Math.sqrt(2);
double d = r * r -2;
if (d == 0)
System.out.println("Radice quadrata di 2 per 2 meno 2 fa 0");
else
System.out.println("Radice quadrata di 2 per 2 meno 2 fa " +
d);
●
Il valore stampato non è zero: d vale
4.440892098500626E-16 che è prossimo a zero,
ma non è zero!
Laboratorio di Programmazione - Luca Tesei
6
Confronti di valori in virgola
mobile
In generale, per confrontare l’uguaglianza di
due valori in virgola mobile è bene fissare una
soglia EPSILON di tolleranza e vedere se i due
valori sono sufficientemente prossimi rispetto a
questa
● Per esempio si può definire
final double EPSILON = 1E-14;
●
E poi controllare se |x-y|  EPSILON. Se è vero
si può decidere che i due valori vanno
considerati “uguali”
●
Laboratorio di Programmazione - Luca Tesei
7
Confronti di valori in virgola
mobile
●
●
Tuttavia, se x e y sono valori molto grandi, la
loro differenza potrebbe essere una quantità
maggiore di EPSILON, ma comunque, vista la
loro grandezza, essere irrisoria
È bene, quando x e y non sono prossimi a zero,
considerare la differenza dei due valori
rapportata alla loro grandezza:
| x y|

max(| x |, | y |)
Laboratorio di Programmazione - Luca Tesei
8
Confronti di valori in virgola
mobile
In codice java:
final double EPSILON = 1E-14;
double x, y;
...
if (Math.abs(x-y) / Math.max(Math.abs(x),
Math.abs(y)) <= EPSILON)
System.out.println(“\”Uguali\””);
else System.out.println(“\”Diversi\””);
●
Laboratorio di Programmazione - Luca Tesei
9
Confronto di Stringhe
●
●
●
●
Le stringhe in Java, lo sappiamo, sono oggetti
Quindi il valore di una variabile di frame di tipo String
non è la stringa in sé, ma un riferimento all’oggetto
stringa
Se cercassimo di confrontare direttamente due variabili
di tipo stringa staremmo semplicemente controllando
se puntano allo stesso oggetto
Ma in generale ciò che ci interessa è sapere se il
contenuto di due stringhe (oggetti stringa diversi) è lo
stesso
Laboratorio di Programmazione - Luca Tesei
10
Confronto di Stringhe
...
String pippo = console.readLine();
String pluto = console.readline();
if (pippo == pluto) //falso
System.out.println(“Stringhe Uguali”)
else System.out,println(“Stringhe Diverse”)
●
●
Per il confronto del contenuto di due stringhe dobbiamo
usare il metodo equals della classe String
Come tipico della programmazione ad oggetti, un
operatore binario fra due oggetti viene realizzato con un
metodo che va chiamato su uno dei due e a cui va
passato un riferimento all’altro oggetto operando
Laboratorio di Programmazione - Luca Tesei
11
Confronto di Stringhe
System.out.println("Inserisci una stringa");
String pippo = console.readLine();
System.out.println("Inserisci una seconda stringa per il confronto");
String pluto = console.readLine();
if ( pippo == pluto )
System.out.println("Confronto con == : Stringhe Uguali");
else
System.out.println("Confronto con == : Stringhe Diverse");
if ( pippo.equals(pluto) )
System.out.println("Confronto con metodo equals: Stringhe” + “
Uguali");
else
System.out.println("Confronto con metodo equals: Stringhe” + “
Diverse");
●
Inserendo due stringhe uguali il primo confronto fallisce, mentre
il secondo ha successo
Laboratorio di Programmazione - Luca Tesei
12
Confronto di Stringhe
●
●
●
La classe String fornisce anche operatori di
confronto “corrispondenti” a <, >
Il metodo compareTo ha un parametro String
in ingresso e confronta la stringa su cui è
chiamato con la stringa passata come
parametro
Il valore di uscita è un int il cui valore indica se
la stringa passata è uguale, “maggiore” o
“minore” nel senso di ordine alfabetico
Laboratorio di Programmazione - Luca Tesei
13
Confronto di Stringhe
int r = string1.compareTo(string2);
● Se r > 0 allora string1 precede string2
nell’ordine alfabetico (lessicografico)
● Se r < 0 allora string1 segue string2
nell’ordine alfabetico (lessicografico)
● Se r == 0 allora le stringhe sono uguali
(alternativa a equals)
Laboratorio di Programmazione - Luca Tesei
14
Confronto di oggetti
●
●
●
Il discorso fatto per le stringhe si applica agli
oggetti in generale
Applicando l’operatore == a due variabili
riferimento si controlla semplicemente se
puntano allo stesso oggetto
Se si vuole invece confrontare lo stato si deve
fornire la classe di un metodo equals simile a
quello che viene fornito con String
Laboratorio di Programmazione - Luca Tesei
15
Ridefinizione di equals
●
Se guardiamo il codice della classe String
vediamo che il metodo equals è così definito:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
Sono esattamente lo stesso oggetto
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
......
Esegue il controllo carattere
}
per carattere, se le stringhe sono
return false;
uguali ritorna true, altrimenti
}
ritorna false
Laboratorio di Programmazione - Luca Tesei
16
Ridefinizione di equals
●
●
●
●
La classe Object definisce un metodo equals
che identifica due oggetti se sono lo stesso,
cioè se i riferimenti puntano alla stessa area di
memoria heap
Ogni classe eredita questo metodo equals
Ogni classe dovrebbe ridefinirlo nello stesso
modo in cui viene fatto nella classe String
Vediamo in dettaglio...
Laboratorio di Programmazione - Luca Tesei
17
Ridefinizione di equals
●
Il metodo deve prendere come parametro un
generico Object:
public boolean equals(Object anObject) {
●
●
●
Per prima cosa controlla se il riferimento
all'oggetto passato è uguale a quello di questo
oggetto
Se è così sicuramente anche bisogna
rispondere true (è ciò che fa equals di Object)
Se non è così allora bisogna controllare il tipo
dell'oggetto passato
Laboratorio di Programmazione - Luca Tesei
18
Ridefinizione di equals
●
L'operatore instanceof restituisce true se un
riferimento generico a Object punta in realtà a
un certo oggetto di una classe data:
if (anObject instanceof String) {
●
●
Se questo non è vero allora bisognerà
rispondere false (due oggetti di classi diverse
in genere non vengono identificati)
Se invece è questo il caso si dovranno
controllare le variabili istanza per decidere
l'uguaglianza...
Laboratorio di Programmazione - Luca Tesei
19
Ridefinizione di equals
●
La prima cosa da fare è un casting per
riottenere un riferimento alla classe vera:
String anotherString = (String) anObject;
●
●
Poi si confronteranno i valori degli oggetti this
e anotherString per decidere se si
considerano questi due oggetti uguali
Non bisogna comunque dimenticare che anche
se equals ridefinito identifica due oggetti
diversi questi rimangono sempre oggetti distinti!
Laboratorio di Programmazione - Luca Tesei
20
Codice hash
●
●
●
●
Se si ridefinisce il metodo equals è sempre
bene ridefinire anche il metodo hashCode della
classe Object
Tale metodo restituisce un intero associato
all'oggetto
Questo valore viene utilizzato come chiave per
inserire l'oggetto in una tabella hash
Non ci addentriamo nei particolari di questa
struttura dati
Laboratorio di Programmazione - Luca Tesei
21
Codice hash
●
●
●
●
Per i nostri scopi ci basta sapere che deve
valere la seguente proprietà:
Se due oggetti sono uguali allora devono avere
lo stesso codice hash
Il viceversa non è richiesto
Se ridefiniamo il metodo equals dobbiamo
quindi ridefinire anche hashCode per rispettare
questa proprietà
Laboratorio di Programmazione - Luca Tesei
22
Codice hash
●
●
●
Un modo per ridefinire il metodo è di scegliere un
numero primo (va bene 31 o 37...)
Per ogni variabile istanza che viene usata nella
definizione di equals si considera il relativo codice
hash
Per questo:
–
Le classi involucro di int, double, etc forniscono il
relativo metodo hashCode
–
String e le altre classi delle API che ridefiniscono
equals forniscono un adeguato hashCode
Laboratorio di Programmazione - Luca Tesei
23
Codice hash
●
●
Supponiamo ad esempio che var1, var2, var3
siano i nomi delle tre variabili istanza che
vengono usate per definire equals
Il codice hash dell'oggetto va allora calcolato così:
int hash = 1;
hash = hash * 31 + var1.hashCode();
hash = hash * 31 + var2.hashCode();
hash = hash * 31 + var3.hashCode();
return hash;
Laboratorio di Programmazione - Luca Tesei
24
Codice hash
●
●
Questo algoritmo va utilizzato soltanto se ci
sono almeno due variabili istanza che
definiscono l'uguaglianza
Se l'uguaglianza è definita solo in base a una
certa variabile istanza si può utilizzare
semplicemente l'hashCode di questa
Laboratorio di Programmazione - Luca Tesei
25
Esempio
●
Consideriamo la classe Persona che
rappresenta una persona
public class Persona{
private String cognome;
private String nome;
private String luogoDiNascita;
private int annoDiNascita, meseDiNascita,
giornoDiNascita;
private double altezza, peso;
...
Laboratorio di Programmazione - Luca Tesei
26
Ridefinizione di equals
●
●
●
●
Supponiamo per ora che una persona sia
distinta dall'altra da cognome, nome, luogo di
nascita e data di nascita
Allora è bene ridefinire il metodo equals
basandosi su queste informazioni
Spesso le informazioni che servono per
ridefinire equals hanno un valore che resta
immutato per tutta la vita dell'oggetto
E' bene quindi definirle final
Laboratorio di Programmazione - Luca Tesei
27
Ridefinizione di equals
public class Persona{
private final String cognome;
private final String nome;
private final String luogoDiNascita;
private final int annoDiNascita, meseDiNascita,
giornoDiNascita;
private double altezza, peso;
private String coloreCapelli, coloreOcchi,
segniParticolari;
.........
Laboratorio di Programmazione - Luca Tesei
28
Ridefinizione di equals
public boolean equals (Object other){
Persona o = null;
if (this == other) return true;
if (other instanceof Persona)
AND Logico
o = (Persona) other;
else return false;
return this.cognome.equals(o.cognome) &&
this.nome.equals(o.nome) &&
this.luogoDiNascita.equals(o.luogoDiNascita) &&
this.annoDiNascita == o.annoDiNascita &&
this.meseDiNascita == o.meseDiNascita &&
this.giornoDiNascita == o.giornoDiNascita; }
Laboratorio di Programmazione - Luca Tesei
29
Ridefinizione di hashcode
●
Ci troviamo nella situazione di più variabili
●
I tipi sono int e String
●
●
Dobbiamo usare i metodi hashcode della classe
Integer e della classe String
Scegliamo il 31 come numero primo di base del
calcolo:
Laboratorio di Programmazione - Luca Tesei
30
Ridefinizione di hashcode
public int hashcode(){
int hash = 1 + 31 * cognome.hashcode();
hash = hash + 31 * nome.hashcode();
hash = hash + 31 * luogoDiNascita.hashcode();
Integer x = new Integer(annoDiNascita);
hash = hash + 31 * x.hashcode();
x = new Integer(meseDiNascita);
hash = hash + 31 * x.hashcode();
x = new Integer(giornoDiNascita);
hash = hash + 31 * x.hashcode(); return hash; }
Laboratorio di Programmazione - Luca Tesei
31
Esercizio
●
●
Aggiungere la variabile istanza String
codiceFiscale e usarla come unico valore di
identificazione dell'oggetto
Ridefinire equals e hashcode di conseguenza
Laboratorio di Programmazione - Luca Tesei
32