il linguaggio java e la progettazione di software object...
TRANSCRIPT
Java 1
Il linguaggio Javae la progettazione di software
object-oriented
Java 2
ANTEFATTO/MOTIVAZIONE: un (cattivo) esempio
• Per realizzare un'applicazione gestionale, di una certa dimensione, vari programmatori sono incaricati di realizzarne parti diverse
• Alberto è incaricato di programmare l'interfaccia utente, e di definire il tipo Data per memorizzare le date.
• Bruno utilizza il tipo Data (definito da Alberto) per scrivere la parte di applicazione che gestisce paghe e contributi
Java 3
Codice C di Alberto Codice C di Bruno
typedef struct {int giorno;int mese;int anno;
} Data;
void stampaData(Data d) {printf("%d", giorno);if (d.mese == 1)
printf("Gen");else if (d.mese == 2)
printf("Feb");…printf("%d", anno);
}
•La manipolazione dei dati avviene con accesso diretto alla rappresentazione del tipo:
Data d;…d.giorno=14;d.mese=12;d.anno=2000;…if (d.giorno == 27)
paga_stipendi();if (d.mese == 12)
paga_tredicesime();…
inizializzazionedi un
oggetto di tipo Data}uso
di un oggetto
di tipo data
Java 4
La definizione di Data cambia!
• Dopo avere rilasciato una prima versione, Alberto modifica la rappresentazione per semplificare “stampaData”
typedef struct {int giorno;char mese[4];int anno;
} Data ;void stampaData(Data d) {
printf("%d", d.giorno); printf("%d", d.mese); printf("%d", d.anno);
}
Java 5
Disastro!
• Il codice scritto da Bruno non funziona più! • Occorre modificarlo:
Data d;…if (d.giorno == 27)
paga_stipendi();if (strcmp(d.mese,"Dic"))
paga_tredicesime()…
Java 6
Le modifiche sono costose
• Se la struttura dati è usata in molti punti del programma, una modifica piccola della struttura comporta tante piccole modifiche.
• Fare tante (piccole) modifiche è:– fonte di errori– lungo e costoso– difficile se documentazione cattiva
• La realizzazione interna (implementazione) delle strutture dati è una delle parti più soggette a cambiamenti (per maggiore efficienza, semplificazione codice...)!
Java 7
Soluzione
• Il problema può essere risolto disciplinando o impedendo l'accesso alla realizzazione della struttura dati.– Bruno non deve più scrivere: (d.mese == 12)
Java 8
Come usare una Data?
• Se si impedisce a Bruno l'accesso ai campi dellastruttura Data, come può Bruno utilizzare le date di Alberto?struct Data {
int giorno;int mese;int anno};
• Il responsabile per Data (Alberto) deve fornire delleoperazioni sufficienti agli utilizzatori o clienti del tipoData (Bruno)
Java 9
Funzioni predefinite per Data
• L’accesso alla struttura dati è fornito unicamente tramite operazioni predefiniteIn C:
void inizializzaData(Data *d, int g, int m, int a) {d->giorno = g; {d->mese = m; d->anno = a;
}
int leggi_giorno(Data d) {return(d.giorno);}
int leggi_mese(Data d){return(d.mese);}
int leggi_anno(Data d){return(d.anno);}
Java 10
Uso delle operazioni predefinite
• Il codice di Bruno è scritto in modo tale da usare solo le operazioni predefinite:
Data d;…
inizializzaData(*d, 14,12,2000);if (leggi_giorno(d) == 27)
paga_stipendi();if (leggi_mese(d) == 12)
paga_tredicesime()…
Java 11
Modifica struttura dati
•Se Alberto cambia la rappresentazione interna di Data, deve modificare anche le operazioni predefinite (ma lasciandone immutato il prototipo):int leggi_mese(Data d){
if (strcmp(d.mese,"Gen")) return(1);…else if (strcmp(d.mese,"Dic")) return(12);}
void inizializzaData(Data *d, int g, int m, int a)) {d->giorno = g;
if (m==1) d->mese = "Gen";…}
•Ma il codice di Bruno non cambia!
Java 12
Incapsulamento
• Abbiamo INCAPSULATO la struttura dati!• Ogni modifica alla struttura resta confinata alla
struttura stessa• Le modifiche sono
– più semplici– più veloci– meno costose
Java 13
Tipo di dato astratto (ADT)
• Astrazione sui dati che non classifica i dati in base a lororappresentazione (IMPLEMENTAZIONE), ma in base a lorocomportamento atteso )(SPECIFICA).
• Il comportamento dei dati è espresso in termini di un insieme di operazioni applicabili a quei dati (INTERFACCIA)
• Le operazioni dell'interfaccia sono le sole che si possono utilizzare per creare, modificare e accedere agli oggetti– L'implementazione della struttura dati non può essere utilizzata al di fuori
della definizione della struttura.• ADT incapsula tutte le operazioni che manipolano i valori del tipo:
– esporta• il nome del tipo• l'interfaccia: tutte e sole le operazioni per manipolare oggetti (cioè dati) del tipo e
la loro specifica– nasconde
• la struttura del tipo• l'implementazione delle operazioni
Java 14
Progettare l'interfaccia
• Interfaccia di un ADT: – "promessa" ai clienti del tipo che le operazioni saranno sempre valide,
anche in seguito a modifiche– deve includere tutte le operazioni utili...
•giorno_dopo: passa al giorno successivo: in C sarebbe:
void giorno_dopo(Data *d){d->giorno++;if (d->giorno > 31){/*ma mesi di 30, 28, 29?*/
d->giorno = 1; d->mese++;if (d->mese > 12) {d->mese = 1; d->anno++;}}
}
• Se la funzione non fosse definita da Alberto, Bruno avrebbedifficoltà a scriverla senza accedere ai campi di una Data.
Java 15
ADT in C?
• C non ha costrutti linguistici diretti per definire ADT (tipoabstracttypedef).
• Bruno potrebbe accedere direttamente ai campi della struct cherappresentano la data. Non possiamo impedirglielo.– Ma con preprocessore, header files, puntatori, prototipi e una certa disciplina
si può separare interfaccia e implementazione.
• C inoltre manca di molte altre astrazioni utili per programmazione in-the-large, che si ritrovano invece nei linguaggi orientati agli oggetti
Java 16
Costrutti per ADT
• Esiste un certo numero di linguaggi di programmazione ("orientati agli oggetti") che: – obbligano ad incapsulare le strutture dati all’interno di opportune
dichiarazioni (CLASSI);– consentono facilmente di impedire l'accesso all'implementazione.
Java 17
Il linguaggio Java
• Definito dalla Sun Microsystems nel 1995/96. Useremo la versione J2SE 1.5 (Java 2 Standard Edition)
• Esistono anche J2EE (Java 2 Enterprise Edition)– costruita sopra J2SE, offre servlets e JSP, EJB…– per sviluppare applicazioni "server side"
• J2ME (Java 2 Micro Edition)– per piccoli dispositivi (telefoni, PDA,…)
Java 18
Caratteristiche
• Object-oriented (OO)• Distribuito
– RMI• Indipendente dalla piattaforma
– Bytecode e Java Virtual Machine• Sicuro
– Esecuzione in una "sandbox" che garantisce che non si possadannegiare l'host
Java 19
Programmazione “in-the-small” e programmazione “in-the-large”
• Programmazione “in piccolo”(in-the-small)– strutturazione del codice per mezzo di astrazioni procedurali– adatta all’implementazione di dettaglio di piccoli programmi– non adatta al progetto di sistemi di grosse dimensione
• Programmazione “in grande” (in-the-large)– astrazione dai dettagli implementativi per concentrarsi sulla struttura
del sistema (information hiding)– il concetto di ADT diventa fondamentale– i linguaggi orientati agli oggetti (per esempio, Java) supportano
esplicitamente la programmazione in grande– usa i principi della programmazione in-the-small per rifinire i dettagli
implementativi
Java 20
Quadro d'insieme
• Programmazione “in the small”– Tipi primitivi– Dichiarazione di variabili– Strutture di controllo: selezione condizionale, cicli
• sono identiche a quelle del C: if, switch, while, for...
– Array (differenze col C)
• Programmazione “in the large”– Classi– Interfacce– Packages
Java 21
Sorpresa!
• Non esistono i "tradizionali" concetti di– "programma"– "sottoprogramma" (funzione o procedura)
• Esistono le classi, che raggruppano (tra le altre cose) dati privati e metodi– i metodi sono il termine OO usato per i sottoprogrammi
(hanno sintassi analoga alle funzioni C)– vedremo tra breve
Java 22
Un’anticipazione: il concetto di classe
ADT in Java
Java 23
La struttura di un programma Java - nozioni preliminari
• Un programma Java è organizzato come un insieme di classi– Ogni classe corrisponde a una dichiarazione di tipo o a una
collezione di funzioni– Classe contiene dichiarazioni di variabili (attributi) e di funzioni
(metodi)
• Il programma principale è rappresentato da un metodo speciale di una classe, detto main
Java 24
Il primo programma Java
file: HelloWorld.java
public class HelloWorld {public static void main(String args[]){
System.out.println(“Hello world!”);}
}
Java 25
Esempio di classe in Java
class Data {private int giorno;private int mese;private int anno;
...public int leggi_giorno(){
//@ ensures (*restituisce il giorno*);public int leggi_mese(){
//@ ensures (*restituisce il mese*);public int leggi_anno(){
//@ ensures (*restituisce l’anno*);}
•class è come struct, ma alcuni campi possono essere funzioni. Dati e funzioni sono incapsulati. I private sono “invisibili all’esterno”, mentre i “public” no.
Java 26
Il costrutto class
• Una classe può essere vista come un tipo definito dall’utente che specifica le operazioni utilizzabili sul tipo stesso. Il tipo può essere usato per dichiarare altre variabili.int a, b;– dichiara due variabili a e b sulle quali è possibile fare tutte le
operazioni predefinite per il tipo int.Data d; – dichiara una variabile d sulla quale è possibile fare tutte le
operazioni definite nella classe Data• Definisce proprio un ADT.
Java 27
Classi, istanze (esemplari), oggetti
• In un programma OO si dichiarano classi per potere definire degli oggetti
• Un oggetto è una entità “viva”, che può essere e modificata e letta tramite operazioni
• Una classe è una sorta di “stampo” per creare oggetti simili ma distinti.– Es. Una classe Data permette di
• dichiarare variabili di tipo Data• Creare oggetti di tipo Data (oggetti e variabili non sono la stessa cosa...)
• Un oggetto è detto istanza (o esemplare) della classe che abbiamo usato come stampo per crearlo
• Si dice anche che l’oggetto appartiene alla classe
Java 28
Attributi di una classe
• La struttura dati di una classe è definita dai suoi attributi
class Data {private int giorno;private int mese;private int anno;...
– giorno, mese, anno sono gli attributi di DataATTRIBU
TI
Java 29
Oggetti
• Tutti gli oggetti della stessa classe hanno la stessa struttura– Il numero e tipo dei loro attributi di istanza è lo stesso– Ad esempio, la classe Data definisce tutte le date possibili, tramite gli attributi giorno,
mese, anno.• Ogni oggetto, in ogni istante dell’esecuzione del programma, è caratterizzato da
uno stato, che è dato dal valore degli attributi dell’oggetto – Lo stato dell’oggetto data1 di tipo Data è definito dal valore degli attributigiorno, mese, anno
Data
giorno = 30mese = 12anno = 2001
data1
nome dell’oggetto nome della classe di cui l’oggetto è istanza
nome e valore degli attributi
Java 30
Oggetti
• Stato di un oggetto– Lo stato rappresenta la condizione in cui si trova l’oggetto– Lo stato è definito dai valori delle variabili interne
all'oggetto (attributi)• Comportamento di un oggetto
– Determina come agisce e reagisce un oggetto– È definito dall’insieme di operazioni che l’oggetto può
compiere (metodi)
Java 31
Metodi di una classe
• Le operazioni definite nella classe sono chiamati i metodi della classe
class Data {...public int leggi_giorno(){...};public int leggi_mese(){...};public int leggi_anno(){...};...
}
M E T O
D I
Java 32
Definizione di metodi
• I metodi definiscono il comportamento degli oggetti appartenenti ad una classe
• Ogni metodo è definito come segue:<tipo val. rit.> <nome.>([<dic. par. formali>]){
<corpo>}
• Il tipo void viene utilizzato per metodi che non restituiscono alcun valore
• (La nozione di metodo ha forti analogie con quella di funzione del linguaggio C)
Java 33
Accesso ad attributi e metodi
• Tramite la "notazione punto"• Esempio:
Data d;int x;...//codice che inizializza d x = d.leggi_giorno();
– Esegue leggi_giorno() su oggetto d: restituisce valore del giorno della data d.– E’ come se leggi_giorno() avesse come argomento implicito d: in C
scriveremmo: leggi_giorno(d);– Si dice anche che all’oggetto d inviamo il messaggio leggi_giorno
Java 34
Qualche cambiamento...
• Cambia la sintassi...– Data d;...if (d.giorno_di_paga())paga_stipendi();
if (d.mese_13esima())paga_tredicesime()
... – L’accesso ad attributi e metodi di un oggetto si effettua tramite la
"notazione punto"
• .. e la terminologia– int a; -- a è una variabile di tipo int– Data d; -- d è una variabile di classe Data
analogia con le struct del C
Java 35
Oggetti mutabilii
• Lo stato degli oggetti (mutabili) può cambiare nel tempo, chiamando metodi opportuni
• NB: Esistono alcuni casi in cui gli oggetti sono immutabili (cioènon possono essere modificati), come ad es. la classe predefinita String
data1.giorno_dopo()
Data
giorno = 30mese = 12anno = 2001
data1
Data
giorno = 31mese = 12anno = 2001
data1
Java 36
Il metodo giorno_dopo()
• Per modificare lo stato, il metodo deve potere accedere ai campidell’oggetto su cui è stato chiamato:
• Nella definizione di un metodo ci si può riferire direttamente (senza notazione punto) ad attributi e metodi dell’oggetto sul quale il metodo sia stato invocato
• class Data {...public void giorno_dopo(){//@ ensures (*incrementa la data*)giorno++;if (giorno > 31){
giorno = 1; mese++;if (mese > 12) {
mese = 1; anno++;}}}…
Data d;…
d.giorno_dopo(); /*modifica lo stato dell’oggetto d*/
Java 37
Private e Public
• Attraverso i metodi "public" di una classe è possibile vedere qual’è lo stato di un oggetto ... – Data d;int x;...x = d.leggi_giorno();
• …ma non accedere ai dati "private" (al di fuori del codice di Data):
if (d.mese ==12)... **Errore di compilazione!**
• Il costrutto di classe consente quindi di definire un tipo di dato astratto.
Java 38
Programmazione "in the small"
Java 39
Tipi primitivi e variabili
• Tipi numerici:– byte: 8 bit– short: 16 bit– int: 32 bit– long: 64 bit– float: 32 bit– double: 64 bit
• Altri tipi:– boolean: true false– char: 16 bit, carattere Unicode
Dichiarazione di variabili
byte un_byte;int a, b=3, c;char c=‘h’, car;boolean trovato=false;
Java 40
Variabili e tipi riferimento
• Tutte le variabili hanno un tipo dichiarato• Le variabili di tipo primitivo (numerico, char, bool) contengono il valore• Tutte le altre contengono riferimenti a valori (ecco perché si dicono
essere "di tipo riferimento")• I tipi riferimento sono:
– Tipi definiti dall’utente (Classi, Interfacce)– Tipi array– Enumerazioni – Le classi sono anche dette tipi riferimento: possono essere usate per
dichiarare variabili che contengono riferimenti– tipi riferimento possono essere utilizzati ovunque si usi un tipo: dichiarazioni
di variabili e parametri, tipo del valore restituito da una funzione... • Le variabili
– consentono di accedere agli oggetti– sono allocate nello stack a run-time quando si chiama il sottoprogramma in
cui sono dichiarate• (gli oggetti referenziati dalle variabili sono invece allocati sullo heap)
– sono deallocate quando il sottoprogramma ritorna al chiamante
Java 41
Ancora su “tipo riferimento”
• Ogni variabile dichiarata con una classe contiene un riferimento a un oggetto: un indirizzo di memoria – il valore effettivo dell’indirizzo non è noto e non interessa
• Un oggetto è memorizzato in una opportuna area di memoria– d, di tipo Data,contiene l’indirizzo della prima cella
dell’oggetto
xxx
113 giorno
mesed
anno1991
Java 42
Dichiarazione e inizializzazione
• La dichiarazione di una variabile di tipo riferimento non alloca spazio per un oggetto, ma solo per il riferimento ad un oggetto
• A una variabile di tipo riferimento è assegnato inizialmente il riferimento null, per indicare che la variabile non è ancora associata ad alcun oggetto
– Es. Data d; d vale null: non esiste ancora un oggetto di tipo Data.
• Un parametro o una variabile locale non possono essere usati senza essere inizializzati (compilatore rileva staticamente mancanza di inizializzazione)
• In entrambi i casi occorre costruire un oggetto e inizializzarlo esplicitamente
Java 43
New
• La costruzione di un oggetto si realizza dinamicamente tramite l’operatore new
• Esempio:Data d = new Data();
Effetto di new: • Costruisce un nuovo oggetto di tipo Data• Restituisce il riferimento all’oggetto appena creato• Il riferimento viene conservato nella variabile d per potere
usare l’oggetto • Data() è un metodo particolare (ha lo stesso nome della
classe, si riconosce come metodo dallE parentesi “()”) chiamato COSTRUTTORE
Java 44
Data data;
data
data = new Data( );
Data
data = new Data( );
Data
Creato con la prima new.
Creato con la prima new.
Creato con la seconda new. Il riferimento al primo oggetto Data è perso.Non c’è più modo di accedere all’oggetto.L’oggetto verrà distrutto dal garbage collector.
Creato con la seconda new. Il riferimento al primo oggetto Data è perso.Non c’è più modo di accedere all’oggetto.L’oggetto verrà distrutto dal garbage collector.
Differenze tra dichiarazione e creazione
Java 45
Dichiarazioni all'internodi un sottoprogrammaint i = 6;int [ ] m = {0, 0, 0};String k = "abcd";Persona y = new Persona();String h;h=k;
La visione a "run-time"
crescita dello stack
6imky
[0, 0, 0]
"abcd"
una persona
h
Java 46
Condivisione (sharing)
• Un oggetto è condiviso tra due variabili se entrambe accedono a esso
• L'assegnamento di variabili di tipo riferimento genera condivisione(vedi k e h nell'esempio precedente)
• Se oggetti condivisi sono modificabili, le modifiche apportateattraverso una variabile sono visibili anche attraverso l'altra (side effect)
Java 47
Conseguenze allocazione stack vs. heap
• Quando un metodo termina, tutte le variabili del corrispondente record di attivazione sono distrutte
• ...pero’ gli oggetti creati sullo heap NON sono necessariamente distrutti public static Data foo() {
Data d = new Data(1,1,1990);return d;
}public static void main(String args[]) {Data x = foo(); ...
/*d esiste solo sullo stack durante l’esecuzione di foo(), ma viene deallocata quando foo() termina. Ma l’oggetto costruito continua a vivere sullo heap!!!*/
xxx11
x
1990
xxx
d
Java 48
Tipi array
• Dato un tipo T (predefinito o definito dall’utente) un array di T è definito come:T[]
• Similmente sono dichiarati gli array multidimensionali:T[][] T[][][] …
• Esempi:int[] float[][] Persona[]
Java 49
Tipi array:dichiarazione e inizializzazione
• Dichiarazione:int[] ai1, ai2;float[] af1;double ad[];Persona[][] ap;
• Inizializzazione:int[] ai={1,2,3};double[][] ad={{1.2, 2.5}, {1.0, 1.5}}
Java 50
Il caso degli array
• In mancanza di inizializzazione, la dichiarazione di un array non alloca spazio per gli elementi dell’array
• L’allocazione si realizza dinamicamente tramite l’operatore: – new <tipo> [<dimensione>]
int[] i=new int[10], j={10,11,12};float[][] f=new float[10][10];Persona[] p=new Persona[30];
• Se gli elementi non sono di un tipo primitivo, l’operatore “new”alloca solo lo spazio per i riferimenti
Java 51
Array di oggetti: Definizione
Person[ ] person;
person = new Person[20];
person[0] = new Person( );
AAE’ definita solo la variabile person. L’array vero e proprio non esiste
E’ definita solo la variabile person. L’array vero e proprio non esiste
person
Java 52
Array di oggetti: Definizione
Person[ ] person;
person = new Person[20];
person[0] = new Person( );BB Ora l’array è stato creato ma
i diversi oggetti di tipo Person non esistono ancora.
Ora l’array è stato creato ma i diversi oggetti di tipo Person non esistono ancora.
person
0 1 2 3 4 16 17 18 19
person
Java 53
Array di oggetti: Definizione
Person[ ] person;
person = new Person[20];
person[0] = new Person( );CC
Un oggetto di tipo persona èstato creato e un riferimento a tale oggetto è stato inserito in posizione 0.
Un oggetto di tipo persona èstato creato e un riferimento a tale oggetto è stato inserito in posizione 0.
0 1 2 3 4 16 17 18 19
person
0 1 2 3 4 16 17 18 19
person
Person
Java 54
Array di oggetti vs. array di tipi base
L’istruzione:float f[] = new float[10];
crea un oggetto di tipo array di float e alloca spazio per 10 float
L’istruzione:Person p[] = new Person[10];
crea un oggetto di tipo array di Person e alloca spazio per 10 riferimenti a oggetti di tipo Person
f0 1 2 3 4 6 7 8 95
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.00.0
f0 1 2 3 4 6 7 8 95
Non viene allocato spazio per gli oggetti
veri e propri
Java 55
Loop generalizzato per collezioni
• Se abbiamo una collezione C di elementi di tipo T, possiamo itrerare su di essi scrivendofor (T x: C) {
esegui azioni su x
}
• anche gli array sono collezioni, quindi …
Java 56
Esempio per array
int sum (int [ ] a) {int result = 0;for (int n : a)
result += n;return result;
}
n indica il generico elementodell'arry, NON l'indice!
Java 57
I concetti fondamentali per la programmazione “in the large”
• Classi• Metodi• Interfacce• Information Hiding• Ereditarietà• Polimorfismo e binding dinamico• Packages
Java 58
Classi e ADT
• Il costrutto di classe consente di definire tipi di datiastratti (ADT)
• Un ADT permette di estendere il linguaggio con nuovi tipi di dato
• Per ottenere un nuovo tipo di dato bisogna definire:– l’insieme dei possibili valori– le operazioni possibili sugli oggetti del tipo
Java 59
Linguaggi orientati agli oggetti
• Il costrutto di classe è caratteristico dei linguaggiorientati agli oggetti (OO)
• Caratteristiche principali (ne vedremo altre)– Incapsulamento delle strutture dati– Protezione, al fine di impedire l'accesso all'implementazione
(information hiding)
Java 60
Definizione di una nuova classe
• Una nuova classe viene definita nel seguente modo:<visibilità> class <nome classe> {<lista di definizioni di attributi, costruttori e metodi>
}
• Esempio:class Automobile {String colore, marca, modello;int cilindrata, numPorte;boolean accesa;
}
attributi
Java 61
Metodi
• I metodi sono procedure che– appartengono agli oggetti (se non si usa la parola chiave
static—vedremo )– hanno come parametro implicito l’oggetto cui appartengono
(this)
Java 62
Definizione di metodi: esempio
class Automobile {String colore, marca, modello;int cilindrata, numPorte;boolean accesa;void accendi() {accesa=true;}boolean puoPartire() {return accesa;}void dipingi(String col) {colore=col;}void trasforma(String ma, String mo) {
marca=ma;modello=mo;
}}
Java 63
Chiamata di metodi-semantica-
1. Vengono valutati i parametri attuali2. Viene creata area dati ("record di attivazione") sullo
stack• spazio per i parametri formali (inizializzati col valore degli
attuali)• spazio per le variabili locali
3. Esecuzione del corpo
si tratta di puntatori agli oggetti,tranne che per il caso dei tipi primitivi
Java 64
Invocazione dei metodi
• Regola per il passaggio parametri:– I parametri il cui tipo sia uno dei tipi semplici sono passati
per copia– I parametri il cui tipo sia un tipo riferimento (classi,
interfacce, array, enumerazioni) sono passati per riferimento (ovvero viene copiato il riferimento)
Java 65
Passaggio parametri e reference: esempio 1
public class Date {public static void reinizializza(Date d) {// riporta d al 31/12/1999
d.day = 31; d.month = 12; d.year = 1999;}public static void main(String[] args) {
11
1990xxxd1
Date d1 = new Date(1,1,1990);
d
Al momento della chiamata:
xxx
Date.reinizializza (d1);
Quando la funzione termina, d1 e' 31/12/1999
1231
1999
Java 66
Passaggio parametri e reference: esempio 2
public class Date {...void copiaIn(Date d) {// copia in d l'oggetto corrente
d.day = day; d.month = month; d.year = year;} public static void main(String[] args) {
11
1990xxxd2
yyy
23d1
1984
Date d1 = new Date(3,2,1984);Date d2 = new Date(1,1,1990);
d
Al momento della chiamata:
xxx
d1.copiaIn(d2); Quando la funzione termina, d2 e' 3/2/1984
23
1984
Java 67
Accesso ad attributi e metodi locali
• Nella definizione di un metodo ci si riferisce ad attributi e metodi dell’oggetto sul quale il metodo sia stato invocato direttamente (senza notazione punto)
• Esempioclass Automobile {String colore;
void dipingi(String col) {colore=col;}...
}
Java 68
Visibilità dei nomi
• Le variabili locali a un metodo (o i parametri formali) possono mascherare gli attributi della classe
• Soluzione:– La pseudo-variabile this contiene un riferimento all’oggetto
corrente e può essere utilizzata per aggirare eventuali mascheramenti
Java 69
this per aggirare mascheramenti
• La pseudo-variabile this contiene un riferimento all’oggetto corrente e può essere utilizzata per aggirare eventuali mascheramentipublic class Automobile {
private String colore, marca, modello;
...public void trasforma(String marca, String modello){this.marca=marca; this.modello=modello;}
}...Automobile a = new Automobile();
a.trasforma(“Ford”, “T4”);
• => a.marca diventa “Ford”, a.modello diventa “T4”
Java 70
La pseudo-variabile this: esempio
• class Data {...public void giorno_dopo(){//MODIFIES: this//REQUIRES: this è una data valida//EFFECTS: incrementa la datathis.giorno++;if (this.giorno > 31){
this.giorno = 1; this.mese++;…
Data d1, d2;…//d1 e d2 inizializzate qui
d1.giorno_dopo(); qui in giorno_dopo this è lo stesso reference di d1.d2.giorno_dopo(); qui in giorno_dopo this è lo stesso reference di d2.
Java 71
this per restituire un reference
• La pseudo-variabile this può essere utilizzata per restituire un riferimento all'oggettocorrente.
• public class InsiemeDiInteri {...
public InsiemeDiInteri inserisci(int i){…//modifica this inserendovi l’elemento ireturn this; //restituisce l‘insieme modificato...
}….}…..InsiemeDiInteri x,y,z;….//qui x e y sono inizializzate opportunamentez = (x.inserisci(2)).unione(y) //utile che inserisci restituisca insieme
Java 72
Oggetti mutabili (richiamo...)
• Lo stato degli oggetti mutabili può cambiare nel tempo, chiamando metodi opportuni
• NB: Esistono alcuni casi in cui gli oggetti sono immutabili (cioè non possono essere modificati), come ad es. la classe predefinita String
data1.giorno_dopo()
Data
giorno = 30mese = 12anno = 2001
data1
Data
giorno = 31mese = 12anno = 2001
data1
Java 73
Oggetti immutabili
• L'oggetto "abcd" (in quanto "String") è immutabile: ilsuo stato non cambia– non esistono operazioni che consentono di modificare lo stato
di un oggetto string• In generale, invece, gli oggetti sono mutabili:
int [ ] x = {0, 0, 0};x[0] = 5;
Java 74
La classe predefinita String
• String in Java è un tipo riferimento (è definito da unaclasse)
• Due regole base:– Variabile di tipo String è un oggetto, manipolato con un reference– le stringhe sono immutabili (non si possono aggiungere o togliere
caratteri a una stringa, ma occorre costruirne una nuova)• (per avere stringhe mutabili si usa StringBuffer)
• Per le stringhe c’è operatore di concatenamento +• Costruttori:
– String() – String(String s) – …
•Metodi (pubblici):
–int length() restituisce la lunghezza di unastringa;
–char charAt(int index) restituisce il char allaposizione index (il primo ha posizione 0)
–String substring(int beginIndex) (parte da 0)
Java 75
La classe String: esempio d’uso
public class ProvaString {//OVERVIEW: …
public static void main (String argv[]) {String a = new String(); //a è reference a stringa vuotaString b = new String("Ciao“); //b è reference a stringa “Ciao”:
//abbreviazione: String b = "Ciao“;String c = new String(b); //Ora c e' copia di bString d = b; //d e b sono aliasSystem.out.println(b + " " + c + " “+ d);}
}L’assegnamento d=b e’ assegnamento dei reference! Non si copia l’oggetto!
Java 76
Private e public
• Attraverso i metodi "public" di una classe è possibile vedere qual èlo stato di un oggetto ... –Data d;int x;...x = d.leggi_giorno();
• …ma non accedere ai dati "private" (al di fuori del codice di Data):if (d.mese ==12)... **Errore di compilazione!**• Il costrutto di classe consente quindi di definire un tipo di dato
astratto.
Java 77
Overloading di metodi
• All’interno di una stessa classe possono esservi più metodi con lo stesso nome purché si distinguano per numero e/o tipo dei parametri– Attenzione: Il tipo del valore di restituito non basta a distinguere due
metodi (motivo: a volte un metodo può essere chiamato solo per i side-effecte valore restituito è ignorato)
• Nozione di SEGNATURA in Java: l’informazione sul numero, il tipo e la posizione dei parametri; NB non include il tipo del valore restituito– Metodi overloaded devono avere segnature diverse
• Utile per definire funzioni con codice differente ma con effetti simili su tipi diversi. Esempio: class prova {int max(int a, int b, int c) {...}double max(double a, double b) {...} int max(int a, int b) {...} }
Ogni volta è chiamata la funzione "giusta"max(2,3,5); max(2.3, 3.14); max(2,3);
Tipico esempio: i costruttori
Java 78
Overloading: un esempio
class C {
int f() {...}
int f(int x) {...} // corretto
void f(int x) {...}
// errato}
C ref = new C();
ref.f();//distinguibile
ref.f(5); //???
Java 79
Argomenti in numero variabile
• In Java 1.5 si possono creare metodi e costruttoricon un numero variabile di argomenti
– public void foo(int count, String... cards) { body }
– “...” significa zero o piu' argomenti (qui, zero o piu' Stringhe)
– Esempio di chiamata foo(13, "ace", "deuce", "trey");– Solo l'ultimo argomento puo' essere un vararg– Possibile iterare, mediante il ciclo for generalizzato:
for (String card : cards) { loop body }
Java 80
Creazione e distruzione degli oggetti
• Se implementazione deve essere private, unico modo per inizializzare un oggetto è specificare uno o più metodi particolari, chiamati costruttori
• La creazione di un oggetto comporta sempre l’invocazione di un costruttore.
• Il costruttore svolge due operazioni fondamentali, obbligandoci a definirle assieme:– l’allocazione della memoria necessaria a contenere l’oggetto– l’inizializzazione dello spazio allocato, assegnando opportuni valori
• A differenza del C, in Java non è necessario deallocare esplicitamente gli oggetti. Di ciò si occupa il garbage collector, che è una routine di sistema che provvede automaticamente a liberare memoria quando serve (invece in C/C++…)
Java 81
Costruttori
• Un costruttore è un metodo speciale: – ha lo stesso nome della classe– il suo codice viene invocato in risposta al messaggio new– tipicamente contiene il codice necessario ad inizializzare gli attributi
dell’oggetto in via di creazione– non ha un tipo del risultato (è implicito nel nome del costruttore)– Si possono definire più costruttori con lo stesso nome (ma numero o tipo dei
parametri deve essere diverso): overloading dei costruttori• Vantaggio: all’allocazione si esegue sempre anche l’inizializzazione,
eliminando una frequente fonte di errori.
Java 82
Esempio di costruttore
public class Date {private int month, day, year;public Date(int d, int m, int y) { // day month year
year = y; month = m; day =d)...}…Date d = new Date(3,12,1987);
Crea un oggetto d di tipo Date e lo inizializza al 3/12/1987
Vantaggio: il metodo Date(...) consente di inizializzare una Data. Ad esempio, potrebbe anche verificare che la data sia legale, “rifiutando” il 31/2/2002
Java 83
Costruttori di default
• Se non si definisce nessun costruttore, il compilatore fornisce il costruttore di default (senza parametri), che svolge le seguenti funzioni:
– Alloca lo spazio per gli attributi di tipo primitivo– Alloca lo spazio per i riferimenti agli attributi di tipo definito dall’utente– Inizializza a null tutti i riferimenti, a 0 tutte le variabili numeriche, a
false tutti i boolean• Il costruttore di default (senza parametri) viene fornito dal
compilatore a meno che non si definiscano altri costruttori
Java 84
I costruttori: esempio
public class C {private int i1;private int i2;
}....public class Esempio {
public static void main(String args[]) {C x;x = new C();x = new C(5,7);
}}
public C() {
i1 = 0; i2 = 0;
}
“omaggio” del compilatore:
non è necessario scriverlo
Corretto perchè il compilatore ha inserito automaticamente il costruttore di default
Sbagliato, non esiste nessun costruttore che prenda due parametri
Java 85
Molti costruttori: esempio
public class C {private int i1;private int i2;public C(int a1, int a2) {
i1 = a1; i2 = a2; }public C(int a) {
i1 = a; i2 = a; }}....public class Esempio {public static void main(String args[]) {
C x, y, z;
}}
Sbagliato, visto che il programmatore ha definito un costruttore, il compilatore non aggiunge quello di default
Corretto, esiste un costruttore che prende un parametro intero
Corretto, esiste un costruttore che prende due parametri interi
x = new C();y = new C(1);
z = new C(1,4);
y C
i1 = 1
i2 = 1
z
C
i1 = 1
i2 = 4x
Java 86
Ulteriore esempio
public class Automobile {private String colore, marca, modello;private int cilindrata, numPorte;private boolean accesa;
public Automobile(String col, String mar, String mod) {colore=col; marca=mar;modello =mod;
}public Automobile() {se serve e’ necessario definirlo anche se e’ come quello di default, perche’ c’e’ un altro costruttore…
colore=marca=modello=null;cilindrata=numPorte=0;
}public void accendi() {accesa=true;}public boolean puoPartire() {return accesa;}public void dipingi(String col) {colore=col;}
}
Java 87
Metodi e attributi di classe
• Sintassi:static <definizione dell’attributo o metodo>
• Un attributo di classe è condiviso da tutti gli oggetti della classe
• Si può accedere a un attributo di classe senza bisogno di creare un oggetto tramite la notazione:<nome classe>.<nome attributo>
• Un metodo di classe può essere invocato senza bisogno di creare un oggetto tramite la notazione:<nome classe>.<nome metodo>(<par. attuali>)
• Un metodo di classe può essere comunque invocato su un oggettodella classe
Java 88
Metodi e attributi di classe: vincoli
• Un metodo static può accedere ai soli attributi e metodi static
• Un metodo convenzionale può accedere liberamente a metodi e attributi static
Java 89
Metodi e attributi di classe: esempio
...Shape.setScreen(new Screen()); // correttoShape.show(); // errato, show è un metodo normaleShape s1=new Shape(), s2=new Shape();Screen s=new Screen();s1.setScreen(s); // corretto, si possono chiamare
// metodi static su oggetti
// in questo punto s2.screen==s1.screen==s
tutte le forme ("shape") vengono visualizzatesu un certo schermo
class Shape {static Screen screen=new Screen(); // si noti l’iniz.static void setScreen(Screen s) {screen=s;}void show(Screen s) {setScreen(s); ...}
}
Java 90
Visione a run time
shape1
shape2
shape3
Allocato
Java 91
Attributi costanti
• È possibile definire attributi costanti tramite la notazione:final <definizione di attributo>=<valore>
• Esempioclass Automobile {
int colore;final int BLU=0, GIALLO=1,...;void dipingi(int colore) {this.colore=colore;}
}...Automobile a=new Automobile();a.BLU=128; // erratoSystem.out.println(“BLU=“+a.BLU); // corretto
Java 92
Ritorniamo al concetto di sharing
xxx
..1
mesed
anno..xxxd1
giorno
d1.giorno =1;
definisce riferimento d a una Data, senza inizializzarlo
Alloca in memoria, in celle consecutive, attributi di Data. d1 diventa l’indirizzo della prima cella
d diventa uguale a d1: l’indirizzo contenuto in d diventa uguale all’indirizzo contenuto in d1 (diventanoalias, cioè nomi diversi per la stessa area di memoria
anche d.giorno diventa 1, poiché d e d1 sono alias
Data d;
Data d1= new Data();
d=d1;
Java 93
Data d = new Data(1,12,2001);
Data d1= new Data(1,12,2001);
if (d==d1) {
...
d=d1;
xxx121 giorno
mese
d
anno2001
yyy121 giorno
mese
d1
anno2001false: d e d1 sono riferimenti a oggettidiversi (anche se hanno gli stessi valori per gliattributi) e quindi hanno indirizzi diversi false
Reference e operatore “== ”
•L’operatore di confronto == confronta i valori dei reference.non gli oggetti!
d == d1 diventa true: l’indirizzo contenuto in d diventa ugualeall’indirizzo contenuto in d1 (diventano identici)
Java 94
Confronto di uguaglianza
– Metodo equals( ) consente di verificare se due oggetti sonouguali (nel senso che hanno lo stesso valore dello stato)
• per string: contengono la stessa sequenza di caratteri
– Uso: stringa1.equals(stringa2))String b = new String("Ciao“);String c = new String("Ciao“);if (b.equals(c))…//true
– NB: NON usare “==” per verificare uguaglianza di stringhe!• “==” dice solo se stanno nella stessa locazione in memoria• NB: la JVM fa condividere le stesse celle alle costanti di tipo
stringa per queste “==” funziona– ma per tutte le altre stringhe usare “==” per il confronto è un errore
Java 95
Risassumendo: riferimenti e oggetti
• Ogni oggetto è dotato di identità univoca– indirizzo (reference) della cella di memoria a cui si trova
l’oggetto
• Assegnamento (=) assegna il valore del reference• Due oggetti possono essere
– uguali: stesso valore dello stato, ma reference diversi• Si verifica con equals
– identici: stesso oggetto (stesso reference)• Si verifica con ==
Java 96
Tipi riferimento per i tipi primitivi
• Tipi primitivi comodi, ma a volte si preferirebbe usarli come riferimento, per omogeneità
• Java fornisce classi predefinite Integer, Character– Un oggetto Integer contiene un int, ma viene inizializzato solo con i
costruttori– Tipo Integer è immutabile– Character classe che contiene char; anche Float, Long, Short, Double
(sono in java.lang)
Integer i; // qui i vale nulli = new Integer(5); //i è un rif. a oggetto che contiene 5Integer x = i; // sharing: x e i sono stesso oggettoint y = x.intValue(); // per accedere a valore di x
NB: Java 1.5 ora fornisce “autoboxing...”
Java 97
Packages e Information Hiding
Java 98
Packages
• Classi (e interfacce, che vedremo tra breve) sonoraggruppate in packages
• Il package raggruppa (incapsula) classi e interfacce, definendo regole di visibilità
• Se visibile nel package A, un'entità X dichiarata nelpackage B viene denotata come B.X – quindi si possono usare liberamente gli stessi nomi in
packages diversi, senza generare confusione
Java 99
La struttura di un programma Java
• Unità di compilazione (Compilation unit)– Ogni compilation unit è un file che contiene la dichiarazione di una o più classi (o
interfacce), delle quali una sola dichiarata pubblica (public class) e avente lo stesso nome del file.
– Es. HelloWorld.java corrisponde a classe pubblica HelloWorld.– C’è al più una sola funzione di nome main– Si può specificare il package di appartenenza di ogni classe nella comp.unit (lo
stesso per tutte)• se non si specifica, si assume un package senza nome di default
• Package– Ogni package è una directory che contiene una o più compilation unit– Il package introduce un nuovo ambito di visibilità dei nomi: unit con lo stesso
nome possono stare in package diversi (corrisponde grossomodo a una libreria...)– Un package contiene un insieme di classi pubbliche ed un insieme di classi private
al package (“friendly”)– Solo le classi pubbliche si possono importare in altri package
Java 100
Information hiding in Java (1)
• Classi possono essere:– public
• sono visibili a tutti con import• file deve avere stesso nome• al più una public class per ogni file
– "friendly":• sono visibili solo all’interno dello stesso package/compilation
unit• possono stare in file con altre classi
Java 101
Esempio
package myTools.text;public class TextComponent {
. . .Zzz z;…}
package myFigs.planar;public class DrawableElement {
. . .}class xxx {
. . .}
package myTools.text;public class yyy {
. . .}class Zzz{
. . .}
compilation units
Java 102
Information hiding (2)
• Attributi e metodi di una classe possono essere:– public
• sono visibili a tutti quelli per cui la classe è visibile
– private• sono visibili solo ai metodi all’interno della stessa classe
– "friendly“ (quando non si indica nulla):• sono visibili solo nelle classi all’interno dello stesso
package/compilation unit: per gli altri package, è come se fossero private
Java 103
Information hiding (3)
• Attenzione: quando si dichiara public un attributo o un metodo di una public class, si fa una promessa, agli utilizzatori della classe, che l’attributo o il metodo saràdisponibile e non cambierà, perlomeno dal punto di vista degli utilizzatori della classe.
• La promessa è molto vincolante, quindi va fatta con cautela! Meglio promettere poco!
• Tutti i metodi e attributi per cui ci si vuole garantire la possibilità di modifica o eliminazione devono essere private (o al massimo, ma solo se indispensabile, friendly). – è meglio private per gli attributi e per tutti i metodi “helper” di
una classe, per garantire che non siano usati accidentalmente nel package, obbligandoci a non poterli più togliere o cambiare
– se attributo è friendly e qualcuno lo usa non possiamo piùcambiarlo!
Java 104
Information hiding (4)
• E' fortemente consigliato che gli attributi di una classe publicsiano private o friendly (usare metodi per accedervi!).
• Invece i metodi che possono essere usati dagli utilizzatori "esterni" della classe dovrebbero essere public.
• Poi vedremo protected…– attributi friendly sono usati solo quando classi all'interno dello
stesso package devono avere accesso privilegiato.• p. es. classe Lista deve usare una classe Nodo che implementa i nodi
della Lista: è utile che Lista possa accedere ai campi di Nodo, ma gli utilizzatori di Lista non devono potere accedere a Nodo
• Questo è un aspetto fondamentale di OO!
Java 105
Il package java.lang
• Il package java.lang contiene classi di uso molto frequente (String, Object, ecc.)
• Non è necessario importare le classi appartenenti al package java.lang prima di utilizzarle
Java 106
Ereditarietà
• E’ possibile stabilire una relazione “sottoclasse_di (⊆) fra le classi di un programma Java– relaz. d’ordine parziale (riflessiva e transitiva)
public class D extends B {…}
• B classe base, o antenato, o padre, o sovraclasse, sopraclasse, superclasse …
• D classe derivata, o discendente, o figlio, o erede, o sottoclasse, …
B
D
Java 107
La relazione di ereditarietà
• La sottoclasse eredita tutta l’implementazione (attributi e metodi) della sopraclasse– Gli attributi e metodi della sopraclasse sono implicitamente
definiti anche nella sottoclasse (ma con alcune differenze che vedremo fra poco…)
• Una sottoclasse può aggiungere nuovi attributi e metodi ma anche....
• ... ridefinire i metodi delle sue sopraclassi (lasciando invariato num. e tipo dei parametri) (overriding)
Java 108
Un semplice esempiopublic class Automobile {
private String modello;private boolean accesa;public Automobile(String modello) {
this.modello=modello; this.accesa = false;}public void accendi() {accesa=true;}public boolean puoPartire() {return accesa;}
}
public class AutomobileElettrica extends Automobile {private boolean batterieCariche;public void ricarica() {batterieCariche=true;}
...}
Java 109
Overriding
• Una sottoclasse può ridefinire l’implementazione di un metodo (ma in tal caso la segnatura del metodo non deve cambiare)– NB: la segnatura NON include il tipo restituito, che quindi può
cambiare secondo le regole della covarianza (vedremo più avanti…)– Esempio:
public class AutomobileElettrica extends Automobile {...
public void accendi() {// OVERRIDING….accensione auto elettrica e’ diversa da quella di auto a
benzina… la reimplementiamo
Java 110
Gerarchia a più livelli
Figure
ClosedFigure OpenFigure
Rectangle
Polygon Ellipse
pixel widthcolorscalerotatedraw
perimeterarea
number_of_sides
Java 111
Accesso ai membri private
• Le sottoclassi non possono accedere agli attributi (e metodi) private delle sopraclassi!
• è sbagliato scrivere: public void accendi() {if(batterieCariche) accesa=true;...;}
perché accesa è private nella sovraclasse!
Java 112
Overriding e la pseudo variabile super
• All’interno (e solo all’interno) di un metodo della sottoclasse ci si può riferire ai metodi della sopraclasse tramite la notazione: super.<nome metodo>(<lista par. attuali>)
– Esempio:public class AutomobileElettrica extends Automobile {
...public void accendi() {// OVERRIDING
if(batterieCariche) super.accendi();else System.out.println("Batterie scariche");}
}
Java 113
Accesso ed ereditarietà
• Attributi e metodi di una classe possono essere:– public
• sono visibili a tutti• vengono ereditati
– private• sono visibili solo all’interno della stessa classe• non sono visibili nelle sottoclassi, ma sono ereditati
– protected (vedremo meglio)• sono visibili solo alle sottoclassi e alle classi nello stesso package• vengono ereditati
– “friendly”: • sono visibili a tutte le classi nello stesso package• vengono ereditati, ma sono visibili alle sottoclassi che stanno nella
stesso package della classe
Java 114
I costruttori non vengono ereditati• I costruttori non sono ereditati perche’ occorre inizializzare
anche i nuovi attributi (costruttore della superclasse non li inizializza)
• Per inizializzare gli attributi private ereditati, all’interno di un costruttore è possibile richiamare il costruttore della sopraclasse tramite la notazione:super(<lista di par. attuali>)
posta come prima istruzione del costruttoreSe il programmatore non chiama esplicitamente un costruttore
della sopraclasse, il compilatore inserisce automaticamente il codice che invoca il costruttore di default della sopraclasse (che potrebbe non esistere!)
– In AutomobileElettrica: public AutomobileElettrica(String modello) {
super(modello); //qui inizializza modello e accesabatterieCariche=false;
}
Java 115
La classe Object
• In mancanza di una differente indicazione, una classe Java estende la classe Object
• La classe Object fornisce alcuni metodi tra i quali vale la pena citare i seguenti:public boolean equals(Object);public String toString();public Object clone();
Java 116
Equals
• Dice se due oggetti sono equivalenti– Che cosa ciò esattamente significhi dipende dal tipo
dell'oggetto• per esempio, due set sono equivalenti se contengono gli
stessi elementi, indipendentemente dall'ordine di inserimento
• va pertanto spesso ridefinita
• L'implementazione fornita da Object coincide con "=="– riferimenti uguali
Java 117
toString
public String toString ( )• Restituisce una rappresentazione testuale dell’oggetto• Implementazione fornita da Object:
– una stringa che mostra il nome del tipo seguito da una rappresentazione testuale del valore dell’oggetto (tipicamente, nomi e valori dei campi racchiusi tra parentesi quadre)
Java 118
clone()
• Il metodo clone restituisce una copia dell'oggetto, nello stesso stato– copia di tutti i campi– (se si vuole che classe fornisca clone, occorre scrivere:
implements Cloneable, altrimenti chiamata a clone() fornita da Object provoca eccezione)
• Cloneable è un’interfaccia: vedremo poi…• Eccezioni: vedremo più avanti…
– Se si vuole fare una copia "completa" dell'oggetto, il metodoclone va ridefinito
• la clone fornita da Object fa una "copia superficiale"• se un attributo è un riferimento, viene copiato il riferimento!
Java 119
Costruire software estendibile usando ereditarietà
Esempio: Progetto tradizionale in C
Figura
Cerchio Rettangolo Triangolo
typedef struct …Figura;
Figura figure[100];
figure[1] = “rettangolo”;figure[2] = “triangolo”;figure[3] = “cerchio”;
void disegnaTutto(Figura *figure) {
for (i= 0; i<100;i++) {if (figure[i] è “rettangolo”)“disegna rettangolo”
if (figure[i] è “triangolo”)“disegna triangolo”if (figure[i] è “cerchio”)“disegna cerchio”
}}
Estendere progetto tradizionale: arriva il Trapezio
Figura
Cerchio Rettangolo Triangolo Trapezio
Codice già definito per disegnaTutto deve
cambiare per potere supportare il nuovo
tipo!!!
typedef struct …Figura;
Figura figure[100];
figure[1] = “rettangolo”;figure[2] = “triangolo”;figure[3] = “cerchio”;figure[4] = “trapezio”
void disegnaTutto(Figura *figure) {
for (i= 0; i<100;i++) {if (figure[i] è “rettangolo”)“disegna rettangolo”if (figure[i] è “triangolo”)
“disegna triangolo”if (figure[i] è “cerchio”)“disegna cerchio”if (figure[i] è “trapezio”)“disegna trapezio
} }
Es. in versione OO
class Cerchiopublic void disegna(){…}
//si definisce classe (astratta) Figura, con metodo (astratto) disegna(), e sue erediRettangolo, Cerchio, Triangolo cheimplementano disegna()
Figura figure = new Figura[100];
figure[1] = new Rettangolo();figure[2] = new Triangolo();figure[3] = new Cerchio();…….disegnaTutto(figure);
public static void disegnaTutto(Figura [] figure) {
for (i= 0; i<100;i++)
figure[i].disegna();}
Quantità di codice è più o meno la stessa di prima, ma èmeglio organizzato...
class Triangolopublic void disegna(){…}
classRettangolopublic void disegna(){…}
class Figurapublic void disegna(){…}
legale in Java: a run-time si decide quale impl. di disegna() chiamare: quella di Cerchio, di Rettangolo, o di Triangolo…
Estendibilità: arriva il Trapezio
Figura figure = new Figura[100];
figure[1] = new Rettangolo();figure[2] = new Triangolo();figure[3] = new Cerchio();figure[4] = new Trapezio();
…disegnaTutto(figure);
public static void disegnaTutto(Figura [] figure) {
for (i= 0; i<100;i++)
figure[i].disegna();
} …ma occorre capire perche’ si può fare cosi’!!!
Codice definito per Figura non
cambia!!!
class Cerchiopublic void disegna(){…}
class Triangolopublic void disegna(){…}
classRettangolopublic void disegna(){…}
class Figurapublic void disegna(){…}
class Trapeziopublic void disegna(){…}
Java 124
Polimorfismo
“Chiave” per costruire software estendile
Java 125
Esempio: codice definito per sopraclasse funziona anche con sottoclasse
public class usaAutomobile {public static int partenza(Automobile p) {
if (p.puoPartire())p.accendi();
…}public static void main(String args[]) {
Automobile myCar = new AutomobileElettrica(“T”);\\ legale!!partenza(myCar); //funziona anche con AutomobileElettrica
....
Vediamo perché tutto funziona come ci aspettiamo….
Java 126
Polimorfismo
• L'esempio precedente è un caso di polimorfismo• Polimorfismo è la capacità per un elemento sintattico
di riferirsi a elementi di diverso tipo• In Java una variabile di un tipo riferimento T può
riferirsi ad un qualsiasi oggetto il cui tipo sia T o un sottotipo di T
• Similmente un parametro formale di un tipo riferimento T può riferirsi a parametri attuali il cui tipo sia T o un sottotipo di T
Java 127
Tipo apparente e tipo effettivo
• Oggetti hanno un tipo apparente (“statico”): quello definitodalla dichiarazione– Es. Automobile myCar;
• Oggetti hanno anche un tipo effettivo (“dinamico”): quello del costruttore usato a run-time per definirlo
• Es. AutomobileElettrica yourCar = new AutomobileElettrica();AutomobileElettrica() restituisce un oggetto di tipo effettivo AutomobileElettrica
• In Java, tipo effettivo può essere sottotipo del tipoapparenteAutomobile myCar = new AutomobileElettrica();
Java 128
Esempio
class AutomobileElettrica extends Automobile {boolean batterieCariche;void ricarica() {batterieCariche=true;}void accendi() {if(batterieCariche) accesa=true;else accesa=false;
}}
Automobile myCar = new Automobile();AutomobileElettrica yourCar = new AutomobileElettrica();. . . myCar = yourCar;
il tipo statico di myCar è Automobilequello dinamico è AutomobileElettrica
Java 129
Regola di assegnamento polimorfico
A un oggetto di tipo apparente T si può sempre assegnare un oggetto il cui tipo apparente S è sottotipo di T (ma non viceversa)
Questo consente che il tipo effettivo possa essere sottotipo di quelloapparente
Automobile myCar = new AutomobileElettrica(); • Il compilatore quindi verifica che ogni oggetto venga manipolato
correttamente solo in base al tipo apparente• La regola precedente però garantisce che a run time non sorgano
errori se invece si opera su un oggetto il cui tipo dinamico è un sottotipo del tipo statico
Java 130
Uso delle classi dell’Esempio: assegnamento
Automobile myCar = new Automobile(“Ford”);AutomobileElettrica yourCar = new AutomobileElettrica(“El”);. . . myCar = yourCar;
Corretto: tipo (apparente) di mycar èsopratipo di tipo (apparente) di yourCar
falsexxx Ford modello
accesamyCar
xxx
falseEl modello
accesayourCar
batterieCarichetrue
Java 131
Uso delle classi dell’Esempio: assegnamento
Automobile myCar = new Automobile();AutomobileElettrica yourCar;. . . yourCar = myCar;
scorretto: tipo (apparente) di yourCar non è sopratipo di tipo (apparente) di myCar
Se questo assegnamento fosse legale, il tipo effettivo potrebbe non essere sottotipo del tipo apparente: non usabile (p.es. senza alcuni metodi pubblici, ecc)
Java 132
Uso delle classi dell’Esempio: assegnamento
Automobile myCar = new AutomobileElettrica();
Corretto: tipo (apparente) di mycar èsopratipo del tipo effettivo
Java 133
Uso delle classi dell’Esempio: assegnamento
AutomobileElettrica yourCar = new Automobile ();
Scorretto: tipo (apparente) di yourCar non è sopratipo del tipo del costruttore
Java 134
Uso delle classi dell’Esempio: chiamata di un metodo
Automobile myCar = new AutomobileElettrica();. . . myCar.puoPartire(); //ok, chiama metodo di AutomobilemyCar.accendi(); //ok, chiama metodo di AutomobileElettricamyCar.ricarica(); //KO, ricarica non è metodo di AutomobileAutomobileElettrica yourCar = new AutomobileElettrica ();yourCar.ricarica(); //OK, chiama metodo di AutomobileElettrica
Java 135
Polimorfismo e binding dinamico
• In Java, a fronte della invocazione x.f(x1,...,xn), l’implementazione scelta per il metodo f dipende dal tipo dinamico di x e non dal suo tipo statico
• Il legame (binding) tra il metodo invocato e il metodoattivato è dinamico, dipende dal tipo attualedell'oggetto. Dispatching è la tecnica usata per realizzare binding dinamico.
Java 136
Esempio
public class usaAutomobile {
public static void main(String args[]) {Automobile a1 = new Automobile(“Ford”);Automobile a2 = new AutomobileElettrica(“T”);a1.accendi(); a run time chiama implementazione di Automobilea2.accendi(); a run time si chiama implementazione di AutomobileElettricapartenza(a2); solo a run time si può conoscere il tipo effettivo
public static int partenza(Automobile a) {a.accendi();//funziona anche con AutomobileElettrica
…}
Java 137
Dispatching (binding dinamico)
• Esempio: static void partenza (Automobile p) {
//accende p e la fa partirep.accendi();
...• Il compilatore non ha modo di stabilire quale implementazione
del metodo accendi() deve chiamare: quella di Automobile o quella di AutomobileElettrica? Il tipo effettivo del parametro p è noto solo quando accendi viene chiamato, cioè a run-time
• Compilatore allora non genera il codice per eseguire il metodo, ma genera codice che cerca qual’è l’implementazione giusta di accendi in base al tipo effettivo di p e la esegue: DISPATCHING– varie tecniche implementative: per es. ogni oggetto può
contenere un puntatore al codice dei propri metodi
Java 138
a1a2
accendipuntatoreal codice
accendi
puntatoreal codice
Implementazione dispatching
Java 139
Overloading e overriding
• Binding dinamico non va confuso con overloadingclass Punto2D{
public float distanza(Punto2D p){…}}class Punto3D extends Punto2D {public float distanza(Punto3D p){…}//OVERLOADING!!!}• Il metodo distanza di Punto3D ha una segnatura diversa da
quella di distanza dichiarato in Punto2D: NON è overridingnon si applica binding dinamico
• Punto2D p = new Punto3D();• p.distanza(p); //chiama Punto2D.distanza(Punto2D)!!!
Java 140
Regola per chiamata metodi
• il compilatore Java, quando trova una chiamata di un metodo: x.m(p); risolve staticamente overloading, individuando la segnatura del metodo chiamato in base al tipo statico X di x e al tipo statico P del parametro attuale p
• Risultato è: X.m(P): in base a regole di overloading viene trovato un metodo di X (o ereditato da X) con parametro il cui tipo è un sopratipo di P. Risultato Y.m(P’) con Y e P’ in generale sopratipi di X e P.
• Binding dinamico si applica a run-time: il codice sceglie a runtime il metodo “più vicino” fra i metodi che hanno il prototipo Y.m(P’) stabilito staticamente.
Java 141
Esempioclass Punto2D{public float distanza(Punto2D…){…}…}class Punto3D extends Punto2D {public float distanza(Punto3D …){…}} //NB distanza overloaded
Punto2D p1,p2;Punto3D p3;p1 = new Punto2D(3,7);p2 = new Punto3D(3,7, 4); System.out.println(p1.distanza(p2)); metodo di Punto2DSystem.out.println(p2.distanza(p1)); Punto2Dp3 = new Punto3D(6,7, 5);System.out.println(p2.distanza(p3)); Punto2D tipo statico di p2 è Punto2DSystem.out.println(p3.distanza(p1)); Punto2D tipo statico di p3 è Punto3D
e tipo statico di p1 è Punto2D scelto distanza(Punto2D)
System.out.println(p1.distanza(p3)); Punto2D tipo statico di p1 è Punto2D scelto distanza(Punto2D)
Punto3D p4 = new Punto3D(6,1, 5);System.out.println(p3.distanza(p4)); tipo statico di p3 è Punto3D
e tipo statico di p4 è Punto3D scelto distanza(Punto3D)
Java 142
Classi e metodi astratti
• Un metodo astratto è un metodo per il quale non viene specificata alcuna implementazione
• Una classe è astratta se contiene almeno un metodo astratto• Non è possibile creare istanze di una classe astratta• Le classi astratte sono molto utili per introdurre delle astrazioni di
alto livello
Java 143
Classi e metodi astratti: esempio
abstract class Shape {static Screen screen;Shape(Screen s) {screen=s;}abstract void show();
}class Circle extends Shape {void show() {... //implementazione del metodo
}}...Shape s=new Shape(); // erratoCircle c=new Circle(); // corretto
Java 144
Classi e metodi final
• Se vogliamo impedire la creazione di sottoclassi di una certa classe la definiremo final
• Esempio:final class C {...}class C1 extends C // errato
• Similmente, se vogliamo impedire l’overriding di un metodo dobbiamo definirlo final
• Esempio:class C { final void f() {...} }
class C1 extends C {void f() {...} // errato
}
Java 145
I limiti dell’ereditarietà semplice
• L’ereditarietà semplice non permette la descrizione di numerose situazioni reali
• Esempio:– Supponiamo di avere una classe Giocattolo ed una classe Automobile. In assenza di ereditarietà multipla non posso definire la classe AutomobileGiocattolo
Java 146
La soluzione di Java
• Distingue tra una gerarchia di ereditarietà (semplice) ed una gerarchia di implementazione (multipla) …
• … introducendo il costrutto interface
Java 147
Interfacce
• Una interfaccia è come una classe che può avere soloattributi costanti e i cui metodi sono tutti pubblici ed astratti
• Sintassi:interface <nome> {<lista di definizione di attributi costanti e metodi privi di corpo>
}
Java 148
Attributi costanti
• Implicitamente, gli attributi dichiarati in una interfacciasono– visibili alla classe che la implementa– immodificabili (static final)
interface scalable {int SMALL=0,MEDIUM=1,BIG=2; //static e final void setScale(int SIZE);
}
Java 149
Interfacce ed ereditarietà
• Una interfaccia può ereditare da una o più interfacce• Sintassi:
interface <nome> extends <nome1>,..,<nomen> {...
}
Java 150
La gerarchia di implementazione• Una classe può implementare una o più interfacce, ma estendere
al più una classe– se la classe non è astratta deve fornire una implementazione per
tutti i metodi presenti nelle interfacce che implementa– altrimenti la classe è astratta
• Sintassi:class <nome> extends <nome0>
implements <nome1>,..,<nomen> {...}
Java 151
Classi e tipi
Java 152
Possibili errori di tipo in un linguaggio
• Assegnamenti tra oggetti di tipo incompatibile• Chiamate di metodi incompatibili (numero e tipo
dei parametri)
Java 153
Tipizzazione forte
• Se il compilatore può garantire che NON sorgano erroridi tipo durante l'esecuzione si dice che il linguaggio èsicuro riguardo ai tipi ("type safe")
• Quando ciò accade si dice che il linguaggio èfortemente tipizzato ("strongly typed")
• Java è fortemente tipizzato
Java 154
Ancora sui tipi in Java
• Rispetto a C, C++:– viene fatta automatica garbage collection
• oggetti accessibili via riferimento sono automaticamentedeallocati quando non più riferiti
ciò evita il pericolo di generare dangling references (riferimentiad aree di memoria deallocata)
– viene fatto controllo automatico a run time che gli indici di un array non escano dai limiti
Java 155
Gerarchia di tipi
• Una classe definisce un tipo• Una sottoclasse (transitivamente) definisce un
sottotipo• Un oggetto del sottotipo è sostituibile a un
oggetto del tipo• Si distingue tra
– tipo statico• il tipo dichiarato
– tipo dinamico (o attuale)• il tipo dell'oggetto attualmente assegnato
Java garantisce che ciò noncomprometta la type safety(vedremo come)
Java 156
Tipo statico e dinamico
• Il compilatore verifica che ogni oggetto vengamanipolato correttamente in base al tipo statico
• Il linguaggio garantisce che a run time non sorgonoerrori se invece si opera su un oggetto il cui tipodinamico è un sottotipo del tipo statico
Java 157
Conversioni automatiche di tipo
Java 158
Promozioni
byte -> short, int, long, float, doubleshort -> int, long, float, double
int -> long, float, doublelong -> float or double
float -> doublechar -> int, long, float, double
Java 159
Conversioni forzate: casting
•È possibile forzare una conversione di tipo attraverso l’operatore di casting:(<tipo>)<espressione>
•Tra tipi primitivi sono consentite le seguenti conversioni forzate (quando possibile e con perdita di informazione)short -> byte, charchar -> byte, shortint -> byte, short, charlong -> byte, short, char, intfloat -> byte, short, char, int, longdouble -> byte, short, char, int, long, floatbyte -> char
Java 160
Casting in generale
• È possibile forzare esplicitamente la conversione da un tipo riferimento T ad un sottotipo T1 purché:– Il tipo dinamico dell’espressione che convertiamo sia un
sottotipo di T1
• Esempio:Animale a = . . .;Gatto mao = . . .;a = mao; // OK, assegnazione polimorfica
mao = (Gatto)a; // corretto (casting) perché a è un gatto
//se non fosse un Gatto eccezione (vedremo)
Java 161
instanceof
• Per evitare errori runtime e stabilire qual’è il tipoeffettivo dell’oggetto estratto con downcasting si puòusare operatore instanceof
Object a;int i = System.in.read(); if (i>0) a = new String(); else a = new Integer();if (a instanceof String) return a.equals(“abcd”);
…
Java 162
Esempio: instanceof e ridefinizione di equals
class Data {private int giorno;private int mese;private int anno;
...public int leggi_giorno(){
...}public boolean equals(Object o) {
if (!(o instanceof Data) return false;Data d= (Data) o;return (giorno==d.giorno && mese == d.mese
&& anno == d.anno)}…
Java 163
ArrayList• Array in Java (come in C) hanno dimensione fissa (anche se sono
oggetti allocati dinamicamente)– Se a un cero punto un array non basta più a contenere gli oggetti, non si può
“allungarlo”: occorre (deallocarlo e) allocarne uno nuovo più capiente: SCOMODO
• ArrayList sono contenitori “estendibili” e “accorciabili” dinamicamente– Prima di JDK5 potevano contenere solo oggetti Object– In JDK5 sono parametrici (generici) rispetto al tipo degli oggetti contenuti– (Prima ancora c’erano i Vector, analoghi ad ArrayList non generici)
ArrayList <Person> team = new ArrayList<Person>();– crea ArrayList privo di elementi e anche di “posizioni” per memorizzarli
• Un ArrayList può essere esteso col metodo add che aggiungeelementi in fondo, oltre a quelli presentiteam.add(new Person(“Bob”,...));team.add(new Person(“Joe”,...));– ora team.size() vale 2
Java 164
• Per gli arrayList non c’è la comoda notazione a[i] utilizzabile per gliarray, occorre usare metodi get e set, che (al solito) fanno riferimento a indici che iniziano da 0
team.get(1); //dà la Person di nome Joeteam.set(0, new Person(“Mary”,...)); //sostituisce Mary a Bob
• NB ArrayList sono implementati come array di puntatori => metodo add allunga di 1 la (parte utilizzata del) l’array– Metodi add(indice, oggetto) e remove(indice) aggiungono e tolgono un
elemento nella posizione indicata, alterando la lunghezza dell’ArrayListteam.add(1, new Person(“Sue”,...));//ora ci sono Mary, Sue, Joeteam.remove(0); // rimuove Mary, ora ci sono Sue e Joe
– NB add e remove comportano “traslazione” di segmenti dell’ArrayList: sonooperazioni “costose” (costo lineare...)
– ATTENZIONE: metodo set NON deve essere usato per inserire un elementoin una posizione che non c’èteam.set(4, new Person(“Jack”,...)); // scorretto
ma solo per sostituire un oggetto già presente in quella posizione
Java 165
• ArrayList sono contenitori => si possono scandire glielementi usando ciclo for-eachfor(Person p: team){
//fa qualcosa con la persona p
}
è equivalente al tradizionale forfor(int i=0; i<team.size(); i++){
Person p = team.get(i);//fa qualcosa con la persona p
}
Java 166
ArrayList, wrappers e autoboxing
• Gli arraylist (come tutti gli altri contenitori) possonocontenere solo oggetti, NON valori di tipi primitivi– per memorizzare valori primitivi bisogna includerli in oggetti
delle classi wrapperArrayList<Integer> intList = newArrayList<Integer>();
intList.add(7);
– viene accettato perchè tradotto (dal compilatore) inintList.add(new Integer(7));
questo si chiama AUTOBOXING– Simmetricamente si può scrivere
int n = intList.get(3);
perchè il metodo per estrarre il valore primitivo viene aggiuntodal compilatore che produce int n = intList.get(3).intValue();
Java 167
Vector (Java<1.5)• Coi Vector (nelle versioni precedenti di Java) si
possono memorizzare solo oggetti Object, quindi in aggiunta occorre anche un casting prima di effettuareun “unwrap”
Vector myVector = new Vector ();myVector.add(new Integer(5));int n = ((Integer)myVector.get(0)).intValue();
Java 168
I/O formattato• JDK 5.0 offre I/O formattato ispirato a C• Per input: costruire uno scanner collegato allo “standar Input Stream”
System.in, poi usare metodi della classe Scanner (nextLine() legge la prossima riga, next() la prossima stringa fino a uno spazio, nextInt() il prossimo int, nextDouble()…, hasNext() dice se c’è una stringa in input, hasNextInt()…, nextFloat()…, nextBoolean()…)
• Per output: System.out fornisce il “buon vecchio” printf di C, con le usuali convenzioni di formattazione, più print e println per stringhe
import java.util.*;...Scanner in = new Scanner(System.in);System.out.println(“Come ti chiami?”);String nome = in.nextLine();System.out.println(“Quanti anni hai?”);int eta = in.nextInt();System.out.println(“Ciao ”+nome+” tra un anno avrai ”+(eta+1)+” anni”);/*oppure: System.out.printf(“Ciao %s tra un anno avrai %d anni”, nome,
eta+1); */...
Java 169
Enumerazioni• In JDK5.0 si possono dichiarare tipi enumerati, per modellare insiemi con
ridotta cardinalitàenum Size {SMALL, MEDIUM, LARGE, EXTRA_LARGE}; Size s = Size.MEDIUM;
• Size è una vera classe: ha esattamente quattro istanze, non se ne possonocostruire altre– (Non c’è bisogno di usare equals per confrontare i valori, basta ==)
• s puo`essere solo null o uno dei valori enumerati• A una classe enumerata si possono aggiungere costruttore, metodi,
attributi: permettono di associare qualsiasi informazione alle costantienumerate– Costruttori invocati solo quando vengono costruite le costantienum Size {SMALL(“S”), MEDIUM(“M”), LARGE(“L”), EXTRA_LARGE(“XL”)
private String abbreviation;private Size(String abbreviation) { //il costruttore
this.abbreviation=abbreviation
}public String getAbbreviation(){return abbreviation;}
};
Java 170
• Tutte classi enumerate eredi della classe Enum che offre i seguentimetodi// dà la costante enumerata della classe indicata che ha quel nomestatic Enum valueOf(Class enumClass, String name) // dà il nome della costante enumerataString toString()
– Molto utili nell operazioni di I/O di valori della classe enumerataScanner in = new Scanner(System,in);String str = in.next(); //e.g. se letta stringa “SMALL”...Size siz = Enum.valueOf(Size, str); //...dà costante Size.SMALLSystem.out.println(Size.LARGE.toString()); //stampa “LARGE”
• Ogni classe enumerata ha un metodo static che restituisce un array contenente tutti i valori della classeSize[] valori = Size.values();
Java 171
• Un esempio più ricco: pianeti del sistema solare, associati alla propria massa e raggio; si può calcolare il peso di un oggetto su ogni pianeta
public enum Planet { MERCURY (3.303e+23, 2.4397e6), VENUS (4.869e+24, 6.0518e6), EARTH (5.976e+24, 6.37814e6), MARS (6.421e+23, 3.3972e6), JUPITER (1.9e+27, 7.1492e7),
SATURN (5.688e+26, 6.0268e7), URANUS (8.686e+25, 2.5559e7), NEPTUNE (1.024e+26, 2.4746e7), PLUTO (1.27e+22, 1.137e6); private final double mass; // in kilogramsprivate final double radius; // in metersPlanet(double mass, double radius) {
this.mass = mass; this.radius = radius; } public double mass() { return mass; } public double radius() {
return radius; } // universal gravitational constant (m3 kg-1 s-2) public static final double G = 6.67300E-11; public double surfaceGravity() {
return G * mass / (radius * radius); } public double surfaceWeight(double otherMass) {
return otherMass * surfaceGravity(); }
}
Java 172
• A partire dal peso di un corpo sulla terra, calcola e stampa il peso su tutti gli altripianeti
public static void main(String[] args) { double earthWeight = Double.parseDouble(args[0]); double mass = earthWeight/EARTH.surfaceGravity(); for (Planet p : Planet.values())
System.out.printf("Your weight on %s is %f%n", p, p.surfaceWeight(mass));
}
$ java Planet 175 Your weight on MERCURY is 66.107583 Your weight on VENUS is 158.374842 Your weight on EARTH is 175.000000 Your weight on MARS is 66.279007 Your weight on JUPITER is 442.847567 Your weight on SATURN is 186.552719 Your weight on URANUS is 158.397260 Your weight on NEPTUNE is 199.207413 Your weight on PLUTO is 11.703031