Interfacce e Polimorfismo Interfacce e Polimorfismo
C. Horstmann
C. Horstmann
Fondamenti di programmazione e Java 2
Fondamenti di programmazione e Java 2
3^ edizione Apogeo
3^ edizione Apogeo
trad. Nicola Fanizzi
trad. Nicola Fanizzi
corso di Programmazione, CdS: Informatica TPS
corso di Programmazione, CdS: Informatica TPS
Dip. di Informatica, Università degli studi di Bari
Dip. di Informatica, Università degli studi di Bari
2 2
Obiettivi Obiettivi
Imparare ad usare le interfacce Imparare ad usare le interfacce
Essere in grado di fare conversioni tra riferimenti a Essere in grado di fare conversioni tra riferimenti a classi e ad interfacce
classi e ad interfacce
Capire il concetto di polimorfismo Capire il concetto di polimorfismo
Imparare ad usare le interfacce per il dis- Imparare ad usare le interfacce per il dis- accoppiamento delle classi
accoppiamento delle classi
3 3
Obiettivi Obiettivi
Imparare ad implementare classi helper come classi Imparare ad implementare classi helper come classi interne
interne
Accedere a variabili del contesto superiore Accedere a variabili del contesto superiore
Implementare eventi ascoltatori (listener) per eventi Implementare eventi ascoltatori (listener) per eventi temporizzatori (timer)
temporizzatori (timer)
4 4
Usare le Interfacce Usare le Interfacce per il Riuso del Codice per il Riuso del Codice
Usare tipi Interfaccia per rendere il codice più Usare tipi Interfaccia per rendere il codice più riusabile
riusabile
Nel Cap. 7 (sulle Iterazioni), abbiamo creato un Nel Cap. 7 (sulle Iterazioni), abbiamo creato un DataSet
DataSet per trovare la media e il massimo di un per trovare la media e il massimo di un insieme di valori (numeri)
insieme di valori (numeri)
Che fare se volessimo trovare media e massimo di Che fare se volessimo trovare media e massimo di un insieme di valori di tipo
un insieme di valori di tipo BankAccount BankAccount ? ?
5 5
Usare le Interfacce Usare le Interfacce per il Riuso del Codice per il Riuso del Codice
public class
public class DataSetDataSet // Modificato per oggetti BankAccount// Modificato per oggetti BankAccount {{
. . . . . .
public void
public void addadd(BankAccount x)(BankAccount x) {
{
sum = sum + x.getBalance();
sum = sum + x.getBalance();
if (count == 0 || maximum.getBalance() < x.getBalance()) if (count == 0 || maximum.getBalance() < x.getBalance()) maximum = x;
maximum = x;
count++;
count++;
} }
public BankAccount
public BankAccount getMaximumgetMaximum() () {
{
return maximum;
return maximum;
} }
private double
private double sumsum; ; private BankAccount
private BankAccount maximummaximum; ; private int
private int countcount; ; } }
6 6
Usare le Interfacce Usare le Interfacce per il Riuso del Codice per il Riuso del Codice
Oppure si supponga di voler trovare la moneta con il Oppure si supponga di voler trovare la moneta con il valore più alto in un insieme di monete
valore più alto in un insieme di monete
Si dovrebbe di nuovo modificare la classe Si dovrebbe di nuovo modificare la classe DataSet
DataSet (come segue...) (come segue...)
7 7
Usare le Interfacce Usare le Interfacce per il Riuso del Codice per il Riuso del Codice
public class
public class DataSetDataSet // Modificata per oggetti Coin// Modificata per oggetti Coin { {
. . . . . .
public void
public void addadd(Coin x) (Coin x) {
{
sum = sum + x.getValue();
sum = sum + x.getValue();
if (count == 0 || maximum.getValue() < x.getValue()) if (count == 0 || maximum.getValue() < x.getValue()) maximum = x;
maximum = x;
count++;
count++;
} }
public Coin
public Coin getMaximumgetMaximum() () {
{
return maximum;
return maximum;
} }
private double
private double sumsum; ; private Coin
private Coin maximummaximum; ; private int
private int countcount; ; } }
8 8
Usare le Interfacce Usare le Interfacce per il Riuso del Codice per il Riuso del Codice
Il funzionamento dell'analisi dei dati è lo stesso in Il funzionamento dell'analisi dei dati è lo stesso in tutti i casi; cambiano i dettagli sulla misura
tutti i casi; cambiano i dettagli sulla misura
Le classi potrebbero accordarsi su un metodo Le classi potrebbero accordarsi su un metodo getMeasure
getMeasure che dà la misura da usare per che dà la misura da usare per l'analisi
l'analisi
Si può implementare una sola classe riusabile Si può implementare una sola classe riusabile DataSet
DataSet il cui metodo il cui metodo add add sia del tipo: sia del tipo:
sum = sum +
sum = sum + xx.getMeasure(); .getMeasure();
if (count == 0 || maximum.getMeasure() <
if (count == 0 || maximum.getMeasure() < xx.getMeasure()) .getMeasure()) maximum =
maximum = xx; ; count++;
count++;
9 9
Usare le Interfacce Usare le Interfacce per il Riuso del Codice per il Riuso del Codice
Qual è il tipo della variabile Qual è il tipo della variabile x x ? ?
x x dovrebbe riferirsi ad una qualsiasi classe che ha il dovrebbe riferirsi ad una qualsiasi classe che ha il metodo
metodo getMeasure getMeasure
In Java, si usa un tipo interfaccia In Java, si usa un tipo interfaccia type per specificare type per specificare operazioni richieste
operazioni richieste
La dichiarazione di una interfaccia elenca i metodi La dichiarazione di una interfaccia elenca i metodi (con le loro firme) richieste dal tipo di interfaccia (con le loro firme) richieste dal tipo di interfaccia
public interface Measurable public interface Measurable { {
double getMeasure();
double getMeasure();
}}
10 10
Confronto Classi - Interfacce Confronto Classi - Interfacce
Un tipo interfaccia è simile ad un tipo di classe Un tipo interfaccia è simile ad un tipo di classe ma vi sono delle importanti differenze:
ma vi sono delle importanti differenze:
Tutti i metodi di un tipo interfaccia sono Tutti i metodi di un tipo interfaccia sono astratti astratti ossia essi ossia essi non hanno una (implementazione nell'interfaccia)
non hanno una (implementazione nell'interfaccia)
Tutti i metodi di un tipo interfaccia sono automaticamente Tutti i metodi di un tipo interfaccia sono automaticamente pubblici
pubblici
Un tipo interfaccia Un tipo interfaccia non non ha campi istanza ha campi istanza
11 11
Dataset
Dataset Generica Generica per Oggetti
per Oggetti Measurable Measurable
public class DataSet public class DataSet { {
. . . . . .
public void add(Measurable x) public void add(Measurable x) {
{
sum = sum + x.getMeasure();
sum = sum + x.getMeasure();
if (count == 0 || maximum.getMeasure() < x.getMeasure()) if (count == 0 || maximum.getMeasure() < x.getMeasure()) maximum = x;
maximum = x;
count++;
count++;
} }
public Measurable getMaximum() public Measurable getMaximum() {
{
return maximum;
return maximum;
} }
private double sum;
private double sum;
private Measurable maximum;
private Measurable maximum;
private int count;
private int count;
}}
12 12
Implementazione Implementazione di un Tipo Interfaccia di un Tipo Interfaccia
Si usa la parola chiave Si usa la parola chiave implements implements per indicare per indicare che una classe implementa un tipo di Interfaccia
che una classe implementa un tipo di Interfaccia
Una classe può implementare Una classe può implementare più di una più di una interfaccia interfaccia
La classe La classe deve deve definire tutti i metodi richiesti da tutte le definire tutti i metodi richiesti da tutte le interfacce che implementa
interfacce che implementa
public class BankAccount implements Measurable public class BankAccount implements Measurable { {
public double getMeasure() public double getMeasure() {
{
return balance;
return balance;
} }
// metodi e campi addizionali // metodi e campi addizionali } }
13 13
Implementazione Implementazione di un Tipo Interfaccia di un Tipo Interfaccia
Altro esempio: Altro esempio:
public class Coin implements Measurable public class Coin implements Measurable { {
public double getMeasure() public double getMeasure() {
{
return value;
return value;
} }
. . . . . . }}
14 14
Diagrammi UML di
Diagrammi UML di Dataset Dataset e Classi Correlate e Classi Correlate
Le interfacce possono ridurre l'accoppiamento tra Le interfacce possono ridurre l'accoppiamento tra classi
classi
Si noti che DataSet Si noti che DataSet è disaccoppiata da è disaccoppiata da BankAccount
BankAccount e da e da Coin Coin
Notazione UML: Notazione UML:
Le interfacce sono etichettate con un indicatore stereotipo Le interfacce sono etichettate con un indicatore stereotipo
«interface»
«interface»
Un arco punteggiato terminante con freccia triangolare Un arco punteggiato terminante con freccia triangolare denota una relazione "
denota una relazione " is-a is-a " ( " ( è-un/una è-un/una ) tra una classe ed ) tra una classe ed un'interfaccia
un'interfaccia
Una linea tratteggiata terminante con freccia triangolare a Una linea tratteggiata terminante con freccia triangolare a V denota una relazione
V denota una relazione di uso di uso o o di dipendenza di dipendenza
15 15
Diagrammi UML di
Diagrammi UML di Dataset Dataset e Classi Correlate e Classi Correlate
Figure 2:
UML Diagram of Dataset Class and the Classes that Implement the Measurable Interface
16 16
Sintassi 11.1:
Sintassi 11.1:
Definire un Interfaccia Definire un Interfaccia
public public interface interface InterfaceName InterfaceName { {
// firme dei metodi // firme dei metodi } }
Esempio Esempio : :
public interface Measurable public interface Measurable { {
double getMeasure();
double getMeasure();
} }
Scopo Scopo : definire una interfaccia e le firme dei suoi : definire una interfaccia e le firme dei suoi metodi che sono automaticamente pubblici
metodi che sono automaticamente pubblici
17 17
Sintassi 11.2:
Sintassi 11.2:
Implementare un'Interfaccia Implementare un'Interfaccia
public class
public class ClassName ClassName implementsimplements InterfaceName, InterfaceName, InterfaceName, InterfaceName, ...
...
{{
// metodi // metodi
// variabili d'istanza// variabili d'istanza }}
Esempio Esempio : :
public class BankAccount implements Measurable public class BankAccount implements Measurable { {
// Other BankAccount methods // Other BankAccount methods public double getMeasure() public double getMeasure() { {
// Method implementation // Method implementation } }
}}
Scopo
Scopo : definire una nuova classe che implementa i metodi di una interfaccia : definire una nuova classe che implementa i metodi di una interfaccia
18 18
DataSetTester.java DataSetTester.java
01: /**01: /**
02:
02: Programma di collaudo per la classe DataSet.Programma di collaudo per la classe DataSet.
03: */03: */
04: public class DataSetTester 04: public class DataSetTester 05: {
05: {
06: public static void main(String[] args) 06: public static void main(String[] args) 07: {
07: {
08: DataSet bankData = new DataSet();
08: DataSet bankData = new DataSet();
09: 09:
10: bankData.add(new BankAccount(0));
10: bankData.add(new BankAccount(0));
11: bankData.add(new BankAccount(10000));
11: bankData.add(new BankAccount(10000));
12: bankData.add(new BankAccount(2000));
12: bankData.add(new BankAccount(2000));
13: 13:
14: System.out.println("Average balance = "
14: System.out.println("Average balance = "
15: + bankData.getAverage());
15: + bankData.getAverage());
16: Measurable max = bankData.getMaximum();
16: Measurable max = bankData.getMaximum();
17: System.out.println("Highest balance = "
17: System.out.println("Highest balance = "
18: + max.getMeasure());
18: + max.getMeasure());
19 19
DataSetTester.java DataSetTester.java
19: 19:
20: DataSet coinData = new DataSet();
20: DataSet coinData = new DataSet();
21: 21:
22: coinData.add(new Coin(0.25, "quarter"));
22: coinData.add(new Coin(0.25, "quarter"));
23: coinData.add(new Coin(0.1, "dime"));
23: coinData.add(new Coin(0.1, "dime"));
24: coinData.add(new Coin(0.05, "nickel"));
24: coinData.add(new Coin(0.05, "nickel"));
25: 25:
26: System.out.println("Average coin value = "
26: System.out.println("Average coin value = "
27: + coinData.getAverage());
27: + coinData.getAverage());
28: max = coinData.getMaximum();
28: max = coinData.getMaximum();
29: System.out.println("Highest coin value = "
29: System.out.println("Highest coin value = "
30: + max.getMeasure());
30: + max.getMeasure());
31: } 31: } 32: } 32: }
20 20
DataSetTester.java DataSetTester.java
Average balance = 4000.0 Average balance = 4000.0 Highest balance = 10000.0 Highest balance = 10000.0
Average coin value = 0.13333333333333333 Average coin value = 0.13333333333333333 Highest coin value = 0.25
Highest coin value = 0.25
Output: Output:
21 21
Conversioni tra Conversioni tra Tipi di Classe e di Interfaccia Tipi di Classe e di Interfaccia
Si può fare una conversione da un tipo di classe ad Si può fare una conversione da un tipo di classe ad uno di interfaccia, ammesso che la classi implementi uno di interfaccia, ammesso che la classi implementi
l'interfaccia l'interfaccia
BankAccount account = new BankAccount(10000);
BankAccount account = new BankAccount(10000);
Measurable x = account;
Measurable x = account; // va bene// va bene
Coin dime = new Coin(0.1, "dime");
Coin dime = new Coin(0.1, "dime");
Measurable x = dime;
Measurable x = dime; // va bene ugualmente// va bene ugualmente
22 22
Conversioni tra Conversioni tra Tipi di Classe e di Interfaccia Tipi di Classe e di Interfaccia
Non si posso fare conversioni tra tipi non correlati Non si posso fare conversioni tra tipi non correlati
perché perché
Rectangle
Rectangle non implementa non implementa Measurable Measurable
Measurable x = new Rectangle(5, 10, 20, 30);
Measurable x = new Rectangle(5, 10, 20, 30); // ERRORE// ERRORE
23 23
Cast Cast
Aggiungere oggetti Aggiungere oggetti Coin Coin ad uno di tipo ad uno di tipo DataSet DataSet
Cosa se ne può fare? Non è di tipo Cosa se ne può fare? Non è di tipo Coin Coin
DataSet coinData = new DataSet();
DataSet coinData = new DataSet();
coinData.add(new Coin(0.25, "quarter"));
coinData.add(new Coin(0.25, "quarter"));
coinData.add(new Coin(0.1, "dime"));
coinData.add(new Coin(0.1, "dime"));
. . . . . .
Measurable max = coinData.getMaximum();
Measurable max = coinData.getMaximum();
// ottiene la moneta più grande // ottiene la moneta più grande
String name = max.getName();
String name = max.getName(); // ERRORE// ERRORE
24 24
Cast Cast
Serve un cast per convertire da un tipo interfaccia ad Serve un cast per convertire da un tipo interfaccia ad un tipo di classe
un tipo di classe
è un oggetto è un oggetto Coin Coin ma il compilatore non lo sa ma il compilatore non lo sa Si applica allora il cast:
Si applica allora il cast:
E si sbaglia e max non è un E si sbaglia e max non è un Coin Coin allora il allora il compilatore lancia un'eccezione
compilatore lancia un'eccezione
Coin maxCoin = (Coin) max;
Coin maxCoin = (Coin) max;
String name = maxCoin.getName();
String name = maxCoin.getName();
25 25
Cast Cast
Differenze con il cast sui numeri: Differenze con il cast sui numeri:
cast sui numeri: cast sui numeri:
si deve essere consapevoli della perdita di informazione si deve essere consapevoli della perdita di informazione
cast su tipi di oggetti: si deve essere consapevoli del cast su tipi di oggetti: si deve essere consapevoli del rischio di causare eccezioni
rischio di causare eccezioni
26 26
Polimorfismo Polimorfismo
Una variabile interfaccia mantiene il riferimento ad un Una variabile interfaccia mantiene il riferimento ad un oggetto della classe che implementa l'interfaccia
oggetto della classe che implementa l'interfaccia Measurable x;
Measurable x;
Si noti che l'oggetto al quale
Si noti che l'oggetto al quale x x si riferisce non il tipo si riferisce non il tipo Measurable
Measurable
Il tipo dell'oggetto è una delle classi che implementano Il tipo dell'oggetto è una delle classi che implementano l'interfaccia
l'interfaccia Measurable Measurable
x = new BankAccount(10000);
x = new BankAccount(10000);
x = new Coin(0.1, "dime");
x = new Coin(0.1, "dime");
27 27
Polimorfismo Polimorfismo
Si può chiamare qualunque metodo dell'interfaccia: Si può chiamare qualunque metodo dell'interfaccia:
Quale metodo viene chiamato ? Quale metodo viene chiamato ?
double m = x.getMeasure();
double m = x.getMeasure();
28 28
Polimorfismo Polimorfismo
Dipende dall'oggetto reale Dipende dall'oggetto reale
Se Se x x si riferisce ad un conto bancario, si chiama si riferisce ad un conto bancario, si chiama BankAccount.getMeasure
BankAccount.getMeasure
Se Se x x si riferisce ad una moneta, si chiama si riferisce ad una moneta, si chiama Coin.getMeasure
Coin.getMeasure
Polimorfismo Polimorfismo ( ( molte forme molte forme ): ):
comportamento che varia a seconda del reale tipo di comportamento che varia a seconda del reale tipo di
un oggetto
un oggetto
29 29
Polimorfismo Polimorfismo
Chiamato anche Chiamato anche late binding late binding : :
risolto al momento dell'esecuzione (a runtime) risolto al momento dell'esecuzione (a runtime)
Diverso dal Diverso dal sovraccarico sovraccarico (overloading): (overloading):
che viene risolto dal compilatore (
che viene risolto dal compilatore ( early binding early binding ) )
30 30
Usare Interfacce per i Callback Usare Interfacce per i Callback
Limiti dell'interfaccia Limiti dell'interfaccia Measurable Measurable : :
Si può aggiungere l'interfaccia Si può aggiungere l'interfaccia Measurable Measurable solo a solo a classi sotto i proprio controllo
classi sotto i proprio controllo
Si può misurare un oggetto solo in una sola maniera Si può misurare un oggetto solo in una sola maniera
Es., non si può analizzare un insieme di risparmi in base Es., non si può analizzare un insieme di risparmi in base
al saldo ed anche al tasso d'interesse al saldo ed anche al tasso d'interesse
Meccanismo del Meccanismo del Callback Callback : consente ad una classe : consente ad una classe di richiamare (
di richiamare ( call back call back ) un metodo specifico quando ) un metodo specifico quando si ha bisogno di maggiore informazione
si ha bisogno di maggiore informazione
31 31
Usare Interfacce per i Callback Usare Interfacce per i Callback
Nella precedente implementazione di Nella precedente implementazione di DataSet DataSet la la responsabilità della misura ricade sugli oggetti stessi responsabilità della misura ricade sugli oggetti stessi
aggiunti aggiunti
Alternativa: passare ad un metodo l'oggetto da Alternativa: passare ad un metodo l'oggetto da misurare
misurare
Object Object è il “ è il “ minimo comune denominatore” minimo comune denominatore” di di tutte le classi
tutte le classi
public interface Measurer public interface Measurer { {
double measure(Object anObject);
double measure(Object anObject);
} }
32 32
Usare Interfacce per i Callback Usare Interfacce per i Callback
Il metodo Il metodo add add chiede al misuratore ( chiede al misuratore ( measurer measurer ) ) e non all'oggetto aggiunto di operare la misura
e non all'oggetto aggiunto di operare la misura
public void add(Object x) public void add(Object x) { {
sum = sum + measurer.measure(x);
sum = sum + measurer.measure(x);
if (count == 0 ||
if (count == 0 ||
measurer.measure(maximum) < measurer.measure(x))measurer.measure(maximum) < measurer.measure(x)) maximum = x;
maximum = x;
count++;
count++;
} }
33 33
Usare Interfacce per i Callback Usare Interfacce per i Callback
Si possono definire classi Si possono definire classi Measurer Measurer specifiche specifiche per poter fare ogni tipo di misura
per poter fare ogni tipo di misura
public class RectangleMeasurer implements Measurer public class RectangleMeasurer implements Measurer { {
public double measure(Object anObject) public double measure(Object anObject) {
{
Rectangle aRectangle = (Rectangle) anObject;
Rectangle aRectangle = (Rectangle) anObject;
double area = double area =
aRectangle.getWidth() * aRectangle.getHeight();
aRectangle.getWidth() * aRectangle.getHeight();
return area;
return area;
} } }}
34 34
Usare Interfacce per i Callback Usare Interfacce per i Callback
Si deve fare il cast da Si deve fare il cast da Object Object a a Rectangle Rectangle
Si passa l'oggetto Si passa l'oggetto Measurer Measurer al costruttore di al costruttore di DataSet
DataSet : :
Rectangle aRectangle = (Rectangle) anObject;
Rectangle aRectangle = (Rectangle) anObject;
Measurer m = new RectangleMeasurer();
Measurer m = new RectangleMeasurer();
DataSet data = new DataSet(m);
DataSet data = new DataSet(m);
data.add(new Rectangle(5, 10, 20, 30));
data.add(new Rectangle(5, 10, 20, 30));
data.add(new Rectangle(10, 20, 30, 40));
data.add(new Rectangle(10, 20, 30, 40));
. . . . . .
35 35
Diagramma UML dell'Interfaccia Diagramma UML dell'Interfaccia
Measurer
Measurer e Classi Correlate e Classi Correlate
Si noti che la classe Si noti che la classe Rectangle Rectangle è disaccoppiata è disaccoppiata dall'interfaccia
dall'interfaccia Measurer Measurer
Figure 2:
UML Diagram of the DataSet Class and the Measurer Interface
36 36
DataSet.java DataSet.java
01: /**
01: /**
02: Calcola la media di un insieme di valori.
02: Calcola la media di un insieme di valori.
03: */
03: */
04: public class DataSet 04: public class DataSet 05: {
05: { 06:
06: /**/**
07: Costruisce un dataset vuoto con un dato measurer.
07: Costruisce un dataset vuoto con un dato measurer.
08: @param aMeasurer il measurer che è usato per 08: @param aMeasurer il measurer che è usato per
// misurare i valori // misurare i valori 09: */
09: */
10: public DataSet(Measurer aMeasurer) 10: public DataSet(Measurer aMeasurer) 11: {
11: {
12: sum = 0;
12: sum = 0;
13: count = 0;
13: count = 0;
14: maximum = null;
14: maximum = null;
15: measurer = aMeasurer;
15: measurer = aMeasurer;
16: } 16: } 17: 17:
37 37
DataSet.java DataSet.java
18: /**
18: /**
19: aggiunge un valore al dataset.
19: aggiunge un valore al dataset.
20: @param x un valore 20: @param x un valore 21: */
21: */
22: public void add(Object x) 22: public void add(Object x) 23: {
23: {
24: sum = sum + measurer.measure(x);
24: sum = sum + measurer.measure(x);
25: if (count == 0 25: if (count == 0
26: || measurer.measure(maximum) 26: || measurer.measure(maximum)
< measurer.measure(x))< measurer.measure(x)) 27: maximum = x;
27: maximum = x;
28: count++;
28: count++;
29: } 29: } 30: 30:
31: /**
31: /**
32: ottiene la media dei valori aggiunti.
32: ottiene la media dei valori aggiunti.
33: @return la media o 0 se nessun dato è stato aggiunto 33: @return la media o 0 se nessun dato è stato aggiunto 34: */
34: */
38 38
DataSet.java DataSet.java
35: public double getAverage() 35: public double getAverage() 36: {
36: {
37: if (count == 0) return 0;
37: if (count == 0) return 0;
38: else return sum / count;
38: else return sum / count;
39: } 39: } 40: 40:
41:
41: /**/**
42:
42: Calcolo l dato più grande.Calcolo l dato più grande.
43:
43: @return massimo o 0 se nessun dato è stato aggiunto@return massimo o 0 se nessun dato è stato aggiunto 44:
44: */*/
45: public Object getMaximum() 45: public Object getMaximum() 46: {
46: {
47: return maximum;
47: return maximum;
48: } 48: } 49: 49:
39 39
DataSet.java DataSet.java
50: private double sum;
50: private double sum;
51: private Object maximum;
51: private Object maximum;
52: private int count;
52: private int count;
53: private Measurer measurer;
53: private Measurer measurer;
54: } 54: }
40 40
DataSetTester2.java DataSetTester2.java
01: import java.awt.Rectangle;
01: import java.awt.Rectangle;
02: 02:
03: /**
03: /**
04: Dimostratore dell'uso di un Measurer.
04: Dimostratore dell'uso di un Measurer.
05: */
05: */
06: public class DataSetTester2 06: public class DataSetTester2 07: {
07: {
08: public static void main(String[] args) 08: public static void main(String[] args) 09: {
09: {
10: Measurer m = new RectangleMeasurer();
10: Measurer m = new RectangleMeasurer();
11: 11:
12: DataSet data = new DataSet(m);
12: DataSet data = new DataSet(m);
13: 13:
14: data.add(new Rectangle(5, 10, 20, 30));
14: data.add(new Rectangle(5, 10, 20, 30));
15: data.add(new Rectangle(10, 20, 30, 40));
15: data.add(new Rectangle(10, 20, 30, 40));
16: data.add(new Rectangle(20, 30, 5, 10));
16: data.add(new Rectangle(20, 30, 5, 10));
17: 17:
18: System.out.println("Average area = " + 18: System.out.println("Average area = " + data.getAverage());
data.getAverage());
19: Rectangle max = (Rectangle) data.getMaximum();
19: Rectangle max = (Rectangle) data.getMaximum();
20: System.out.println("Maximum area rectangle = " +max);
20: System.out.println("Maximum area rectangle = " +max);
21: } 21: }
41 41
Measurer.java Measurer.java
01: /**
01: /**
02: Descrive ogni classe i cui oggetti possono misurare 02: Descrive ogni classe i cui oggetti possono misurare altri oggetti.
altri oggetti.
03: */
03: */
04: public interface Measurer 04: public interface Measurer 05: {
05: {
06: /**
06: /**
07: Calcola la misura di un oggeto.
07: Calcola la misura di un oggeto.
08: @param anObject l'oggetto da misurare 08: @param anObject l'oggetto da misurare 09: @return la misura
09: @return la misura 10: */
10: */
11: double measure(Object anObject);
11: double measure(Object anObject);
12: } 12: }
42 42
RectangleMeasurer RectangleMeasurer
01: import java.awt.Rectangle;
01: import java.awt.Rectangle;
02:02:
03: /**
03: /**
04: Gli oggetti di questa classe misurano i rettengoli in 04: Gli oggetti di questa classe misurano i rettengoli in base all'area.
base all'area.
05: */
05: */
06: public class RectangleMeasurer implements Measurer 06: public class RectangleMeasurer implements Measurer 07: {
07: {
08: public double measure(Object anObject) 08: public double measure(Object anObject) 09: {
09: {
10: Rectangle aRectangle = (Rectangle) anObject;
10: Rectangle aRectangle = (Rectangle) anObject;
11: double area = aRectangle.getWidth() 11: double area = aRectangle.getWidth()
* aRectangle.getHeight();* aRectangle.getHeight();
12: return area;
12: return area;
13: } 13: } 14: } 14: } 15: 15:
43 43
RectangleMeasurer RectangleMeasurer
Average area = 616.6666666666666 Average area = 616.6666666666666
Maximum area rectangle = java.awt.Rectangle[x=10,y=20, Maximum area rectangle = java.awt.Rectangle[x=10,y=20, // width=30,height=40] // width=30,height=40]
Output Output
44 44
Classi Interne Classi Interne
Una classe semplice può essere definita all'interno di Una classe semplice può essere definita all'interno di un metodo
un metodo
public class DataSetTester3 public class DataSetTester3 { {
public static void main(String[] args) public static void main(String[] args)
{ {
class RectangleMeasurer implements Measurer class RectangleMeasurer implements Measurer
{ {
. . . . . .
} }
Measurer m = new RectangleMeasurer();
Measurer m = new RectangleMeasurer();
DataSet data = new DataSet(m); . . . DataSet data = new DataSet(m); . . .
} } } }
45 45
Classi Interne Classi Interne
Se una classe interna viene definita all'interno del Se una classe interna viene definita all'interno del contesto di un'atra classe,
contesto di un'atra classe, ma al di fuori dei metodi, ma al di fuori dei metodi,
essa è visibile a tutti i metodi della classe esterna essa è visibile a tutti i metodi della classe esterna
Il compilatore converte una classe interna in un Il compilatore converte una classe interna in un normale file di classe:
normale file di classe:
DataSetTester$1$RectangleMeasurer.class DataSetTester$1$RectangleMeasurer.class
46 46
Sintassi 11.3: Classi Interne Sintassi 11.3: Classi Interne
Dichiarata in un metodo Dichiarata in un metodo class
class NomeClasseEsterna NomeClasseEsterna { {
firma di metodofirma di metodo { {
. . .
class NomeClasseInterna class NomeClasseInterna
{ {
// metodi // metodi
// campi // campi
} }
. . . } }
. . . . . . } }
Dichiarata in una classe Dichiarata in una classe class
class NomeClasseEsterna NomeClasseEsterna { {
// metodi // metodi
// campi // campi
accessSpecifier class accessSpecifier class
NomeClasseInternaNomeClasseInterna
{ {
// metodi // metodi
// campi // campi
} } . . . . . . }}
47 47
Sintassi 11.3: Classi Interne Sintassi 11.3: Classi Interne
Esempio: Esempio:
public class Tester public class Tester { {
public static void main(String[] args) public static void main(String[] args) { {
class RectangleMeasurer implements Measurer class RectangleMeasurer implements Measurer
{ {
. . .
} }
. . . } }
}}
Scopo Scopo : definire una classe interna la cui visibilità è : definire una classe interna la cui visibilità è limitata a un singolo metodo o ai metodi di una
limitata a un singolo metodo o ai metodi di una singola classe
singola classe
48 48
FileTester3.java FileTester3.java
01: import java.awt.Rectangle;
01: import java.awt.Rectangle;
02: 02:
03: /**
03: /**
04: Questo programma mostra l'uso di Measurer.
04: Questo programma mostra l'uso di Measurer.
05: */
05: */
06: public class DataSetTester3 06: public class DataSetTester3 07: {
07: {
08: public static void main(String[] args) 08: public static void main(String[] args) 09: {
09: {
10: class RectangleMeasurer implements Measurer 10: class RectangleMeasurer implements Measurer 11: {
11: {
12: public double measure(Object anObject) 12: public double measure(Object anObject) 13: {
13: {
14: Rectangle aRectangle = (Rectangle) anObject;
14: Rectangle aRectangle = (Rectangle) anObject;
15: double area 15: double area
16: = aRectangle.getWidth() 16: = aRectangle.getWidth()
* aRectangle.getHeight();* aRectangle.getHeight();
17: return area;
17: return area;
49 49
FileTester3.java FileTester3.java
18: } 18: } 19: } 19: } 20: 20:
21: Measurer m = new RectangleMeasurer();
21: Measurer m = new RectangleMeasurer();
22: 22:
23: DataSet data = new DataSet(m);
23: DataSet data = new DataSet(m);
24: 24:
25: data.add(new Rectangle(5, 10, 20, 30));
25: data.add(new Rectangle(5, 10, 20, 30));
26: data.add(new Rectangle(10, 20, 30, 40));
26: data.add(new Rectangle(10, 20, 30, 40));
27: data.add(new Rectangle(20, 30, 5, 10));
27: data.add(new Rectangle(20, 30, 5, 10));
28: 28:
29: System.out.println("Average area = " + 29: System.out.println("Average area = " + data.getAverage());
data.getAverage());
30: Rectangle max = (Rectangle) data.getMaximum();
30: Rectangle max = (Rectangle) data.getMaximum();
31: System.out.println("Maximum area rectangle = " + max);
31: System.out.println("Maximum area rectangle = " + max);
32: } 32: } 33: } 33: }
50 50
Elaborare eventi di Elaborare eventi di
temporizzazione temporizzazione
La classe La classe Timer Timer nel pacchetto nel pacchetto javax.swing javax.swing genera una sequenza di eventi, separati da intervalli genera una sequenza di eventi, separati da intervalli
di tempo tutti uguali fra loro di tempo tutti uguali fra loro
Ciò è utile ogni volta si vuole disporre di oggetti Ciò è utile ogni volta si vuole disporre di oggetti aggiornati a intervalli regolari
aggiornati a intervalli regolari
Un ricevitore di eventi ( Un ricevitore di eventi ( listener listener ) riceve una notifica ) riceve una notifica quando accade un particolare evento
quando accade un particolare evento
public interface ActionListener public interface ActionListener {{
void actionPerformed(ActionEvent event);
void actionPerformed(ActionEvent event);
} }
51 51
Elaborare eventi di Elaborare eventi di
temporizzazione temporizzazione
Dovete definire una classe che realizzi l’interfaccia Dovete definire una classe che realizzi l’interfaccia ActionListener
ActionListener
class MyListener implements ActionListener class MyListener implements ActionListener {{
void actionPerformed(ActionEvent event) void actionPerformed(ActionEvent event) { {
// questa azione verrà eseguita a ogni // questa azione verrà eseguita a ogni
// evento di temporalizzazione// evento di temporalizzazione
Inserite qui le azioni del ricevitore di eventiInserite qui le azioni del ricevitore di eventi } }
}}
52 52
Elaborare eventi di Elaborare eventi di
temporizzazione temporizzazione
Costruire un oggetto di tale classe e Costruire un oggetto di tale classe e passarlo al costruttore di
passarlo al costruttore di Timer Timer . .
MioRicevitore listener = new MioRicevitore listener = new MioRicevitore();
MioRicevitore();
Timer t = new Timer(interval, listener);
Timer t = new Timer(interval, listener);
t.start();
t.start();
53 53
Esempio: Temporizzatore Esempio: Temporizzatore
Esempio Esempio : un temporizzatore che conta all’indietro : un temporizzatore che conta all’indietro
Figura 3:
esecuzione del programma TimeTester
54 54
TimeTester.java TimeTester.java
01: import java.awt.event.ActionEvent;
01: import java.awt.event.ActionEvent;
02: import java.awt.event.ActionListener;
02: import java.awt.event.ActionListener;
03: import javax.swing.JOptionPane;
03: import javax.swing.JOptionPane;
04: import javax.swing.Timer;
04: import javax.swing.Timer;
05: 05:
06: /**
06: /**
07: Questo programma collauda la classe Timer.
07: Questo programma collauda la classe Timer.
08: */
08: */
09: public class TimerTester 09: public class TimerTester 10: {
10: {
11: public static void main(String[] args) 11: public static void main(String[] args) 12: {
12: {
13: class CountDown implements ActionListener 13: class CountDown implements ActionListener 14: {
14: {
15: public CountDown(int initialCount) 15: public CountDown(int initialCount) 16: {
16: {
17: count = initialCount;
17: count = initialCount;
18: } 18: }
55 55
TimeTester.java TimeTester.java
19: 19:
20: public void actionPerformed(ActionEvent event) 20: public void actionPerformed(ActionEvent event) 21: {
21: {
22: if (count >= 0) 22: if (count >= 0)
23: System.out.println(count);
23: System.out.println(count);
24: if (count == 0) 24: if (count == 0)
25: System.out.println("Liftoff!");
25: System.out.println("Liftoff!");
26: count--;
26: count--;
27: } 27: } 28: 28:
29: private int count;
29: private int count;
30: } 30: } 31: 31:
32: CountDown listener = new CountDown(10);
32: CountDown listener = new CountDown(10);
33: 33:
34: final int DELAY = 1000;
34: final int DELAY = 1000; // Millisecondi fra gli // Millisecondi fra gli
eventi eventi
56 56
TimeTester.java TimeTester.java
35: Timer t = new Timer(DELAY, listener);
35: Timer t = new Timer(DELAY, listener);
36: t.start();
36: t.start();
37: 37:
38: JOptionPane.showMessageDialog(null, "Quit?");
38: JOptionPane.showMessageDialog(null, "Quit?");
39: System.exit(0);
39: System.exit(0);
40: } 40: } 41: } 41: }
57 57
Accesso alle Variabili Circostanti Accesso alle Variabili Circostanti
I metodi di una classe interna possono accedere alle I metodi di una classe interna possono accedere alle variabili dell’ambito di visibilità circostante.
variabili dell’ambito di visibilità circostante.
Utile per la realizzazione di gestori di eventi, perché Utile per la realizzazione di gestori di eventi, perché consente alla classe interna di accedere alle variabili consente alla classe interna di accedere alle variabili
senza che ci sia bisogno di passarle come parametri senza che ci sia bisogno di passarle come parametri
Esempio: Esempio:
utilizzare un temporizzatore per allestire un’animazione; utilizzare un temporizzatore per allestire un’animazione;
si sposterà una forma in una diversa posizione, dieci volte si sposterà una forma in una diversa posizione, dieci volte al secondo.
al secondo.
58 58
Accesso alle Variabili Circostanti Accesso alle Variabili Circostanti
class Mover implements ActionListener class Mover implements ActionListener { {
public void actionPerformed(ActionEvent event) public void actionPerformed(ActionEvent event) {
{
// sposta il rettangolo// sposta il rettangolo }
} } }
ActionListener listener = new Mover();
ActionListener listener = new Mover();
final int DELAY = 100;
final int DELAY = 100;
// Millisecondi fra due eventi di temporizzazione // Millisecondi fra due eventi di temporizzazione Timer t = new Timer(DELAY, listener);
Timer t = new Timer(DELAY, listener);
t.start();
t.start();
59 59
Accesso alle Variabili Circostanti Accesso alle Variabili Circostanti
Il metodo Il metodo actionPerformed actionPerformed può accedere alle può accedere alle variabili che si trovano nell’ambito di visibilità
variabili che si trovano nell’ambito di visibilità circostante, in questo modo:
circostante, in questo modo:
public static void main(String[] args) public static void main(String[] args) { {
. . . . . .
final Rectangle box = new Rectangle(5, 10, 20, 30);
final Rectangle box = new Rectangle(5, 10, 20, 30);
class Mover implements ActionListener class Mover implements ActionListener {
{
public void actionPerformed(ActionEvent event) public void actionPerformed(ActionEvent event) {
{
// sposta il rettangolo// sposta il rettangolo box.translate(1, 1);
box.translate(1, 1);
} } } }
. . . . . . } }
60 60
Accesso alle Variabili Circostanti Accesso alle Variabili Circostanti
Le variabili locali a cui si accede da un metodo di Le variabili locali a cui si accede da un metodo di una classe interna devono essere dichiarate
una classe interna devono essere dichiarate final final
Una classe interna può accedere ai campi di Una classe interna può accedere ai campi di
esemplare della classe circostante, ma il campo esemplare della classe circostante, ma il campo
deve appartenere all’oggetto che ha costruito deve appartenere all’oggetto che ha costruito
l’esemplare della classe interna l’esemplare della classe interna
Se l’esemplare di classe interna viene costruito Se l’esemplare di classe interna viene costruito all’interno di un metodo statico, può accedere all’interno di un metodo statico, può accedere
solamente alle variabili statiche della classe solamente alle variabili statiche della classe
circostante
circostante
61 61
TimeTester2.java TimeTester2.java
01: import java.awt.Rectangle;
01: import java.awt.Rectangle;
02: import java.awt.event.ActionEvent;
02: import java.awt.event.ActionEvent;
03: import java.awt.event.ActionListener;
03: import java.awt.event.ActionListener;
04: import javax.swing.JOptionPane;
04: import javax.swing.JOptionPane;
05: import javax.swing.Timer;
05: import javax.swing.Timer;
06: 06:
07: /**
07: /**
08: Questo programma utilizza un temporizzatore per spostare 08: Questo programma utilizza un temporizzatore per spostare
un rettangolo dieci volte al secondo.un rettangolo dieci volte al secondo.
09: */
09: */
10: public class TimerTester2 10: public class TimerTester2
11: { 11: {
12: public static void main(String[] args) 12: public static void main(String[] args)
13: { 13: {
14: final Rectangle box = new Rectangle(5, 10, 20, 30);
14: final Rectangle box = new Rectangle(5, 10, 20, 30);
15: 15:
16: class Mover implements ActionListener 16: class Mover implements ActionListener
17: { 17: {
62 62
TimeTester2.java TimeTester2.java
18: public void actionPerformed(ActionEvent event) 18: public void actionPerformed(ActionEvent event) 19: {
19: {
20: box.translate(1, 1);
20: box.translate(1, 1);
21: System.out.println(box);
21: System.out.println(box);
22: } 22: } 23: } 23: } 24: 24:
25: ActionListener listener = new Mover();
25: ActionListener listener = new Mover();
26: 26:
27: final int DELAY = 100;
27: final int DELAY = 100; // Millisecondi fra due eventi// Millisecondi fra due eventi
di temporalizzazionedi temporalizzazione 28: Timer t = new Timer(DELAY, listener);
28: Timer t = new Timer(DELAY, listener);
29: t.start();
29: t.start();
30: 30:
31: JOptionPane.showMessageDialog(null, "Quit?");
31: JOptionPane.showMessageDialog(null, "Quit?");
32: System.out.println("Last box position: " + box);
32: System.out.println("Last box position: " + box);
33: System.exit(0);
33: System.exit(0);
34: } 34: } 35: } 35: }
63 63
TimeTester2.java TimeTester2.java
java.awt.Rectangle[x=6,y=11,width=20,height=30]
java.awt.Rectangle[x=6,y=11,width=20,height=30]
java.awt.Rectangle[x=7,y=12,width=20,height=30]
java.awt.Rectangle[x=7,y=12,width=20,height=30]
java.awt.Rectangle[x=8,y=13,width=20,height=30] . . . java.awt.Rectangle[x=8,y=13,width=20,height=30] . . . java.awt.Rectangle[x=28,y=33,width=20,height=30]
java.awt.Rectangle[x=28,y=33,width=20,height=30]
java.awt.Rectangle[x=29,y=34,width=20,height=30]
java.awt.Rectangle[x=29,y=34,width=20,height=30]
Last box position:
Last box position:
java.awt.Rectangle[x=29,y=34,width=20,height=30]
java.awt.Rectangle[x=29,y=34,width=20,height=30]