Upload
buibao
View
217
Download
0
Embed Size (px)
Citation preview
1Laboratorio di Programmazione - Luca Tesei
Confronti, equals
Operatori Relazionali, confronti
Confronti fra Oggetti, ridefinizione di equals
2Laboratorio di Programmazione - Luca Tesei
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:
3Laboratorio di Programmazione - Luca Tesei
Operatori Relazionali
Diverso!=
Uguale===
Minore o uguale<=
Minore<<
Maggiore o uguale>=
Maggiore>>
DescrizioneNotazione matematicaOperatore Java
4Laboratorio di Programmazione - Luca Tesei
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
5Laboratorio di Programmazione - Luca Tesei
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
6Laboratorio di Programmazione - Luca Tesei
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!
7Laboratorio di Programmazione - Luca Tesei
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ò definirefinal double EPSILON = 1E-14;● E poi controllare se |x-y| EPSILON. Se è vero
si può decidere che i due valori vanno considerati “uguali”
8Laboratorio di Programmazione - Luca Tesei
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:
|)||,max(|
||
yx
yx
9Laboratorio di Programmazione - Luca Tesei
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\””);
10Laboratorio di Programmazione - Luca Tesei
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
11Laboratorio di Programmazione - Luca Tesei
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
12Laboratorio di Programmazione - Luca Tesei
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
13Laboratorio di Programmazione - Luca Tesei
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
14Laboratorio di Programmazione - Luca Tesei
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)
15Laboratorio di Programmazione - Luca Tesei
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
16Laboratorio di Programmazione - Luca Tesei
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;}if (anObject instanceof String) { String anotherString = (String) anObject; ......}return false;}
Esegue il controllo carattereper carattere, se le stringhe sono
uguali ritorna true, altrimenti ritorna false
Sono esattamente lo stesso oggetto
17Laboratorio di Programmazione - Luca Tesei
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...
18Laboratorio di Programmazione - Luca Tesei
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
19Laboratorio di Programmazione - Luca Tesei
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...
20Laboratorio di Programmazione - Luca Tesei
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!
21Laboratorio di Programmazione - Luca Tesei
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
22Laboratorio di Programmazione - Luca Tesei
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à
23Laboratorio di Programmazione - Luca Tesei
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
24Laboratorio di Programmazione - Luca Tesei
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;
25Laboratorio di Programmazione - Luca Tesei
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
26Laboratorio di Programmazione - Luca Tesei
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;
...
27Laboratorio di Programmazione - Luca Tesei
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
28Laboratorio di Programmazione - Luca Tesei
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;
.........
29Laboratorio di Programmazione - Luca Tesei
Ridefinizione di equals
public boolean equals (Object other){
Persona o = null;
if (this == other) return true;
if (other instanceof Persona)
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; }
AND Logico
30Laboratorio di Programmazione - Luca Tesei
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:
31Laboratorio di Programmazione - Luca Tesei
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; }