• Per realizzare un`applicazione gestionale, di una certa dimensione

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
Il linguaggio Java
e la progettazione di software
object-oriented
Java
Codice C di Alberto
1
•La manipolazione dei dati
avviene con accesso diretto alla
rappresentazione del tipo:
Data d;
…
d.giorno=14;
inizializzazione
di un
d.mese=12;
oggetto di tipo Data
d.anno=2000;
…
uso
if (d.giorno == 27)
di un
paga_stipendi();
oggetto
if (d.mese == 12)
di tipo data
paga_tredicesime();
…
void stampaData(Data d) {
printf("%d", giorno);
if (d.mese == 1)
printf("Gen");
else if (d.mese == 2)
printf("Feb");
…
printf("%d", anno);
}
}
Java
2
Richiami sui tipi di dati
Codice C di Bruno
typedef struct {
int giorno;
int mese;
int anno;
} Data;
Java
3
• Tipo = insieme di valori + insieme di operazioni
• Es. int:
– valori: …, -2, -1, 0, 1, 2, …
– operazioni:: +,-,*,/, <, == …
– le operazioni si applicano a entità (oggetti) di tipo int.
• Tipi built-in (primitivi in Java): int, float, char, double,..
– Per i tipi primitivi, il dominio e le operazioni possibili sono definite dal
linguaggio
• Tipi definiti dall’utente
– Costruttori di tipo: definiscono nuovi tipi composti a partire da altri tipi (array,
struct, ...)
– Operazioni predefinite anche per i costruttori di tipo (a.y, b[i], ecc.)
– Strutture dati complesse possono essere costruite partendo dai tipi semplici
tramite i costruttori di tipo.
Java
4
Vantaggi del concetto di tipo
La definizione di Data cambia!
• Dopo avere rilasciato una prima versione, Alberto modifica la
rappresentazione per semplificare “stampaData”
• Classificare i dati:
– Programmatore non deve occuparsi di celle di memoria
(astrazione sulla struttura di rappresentazione)
typedef struct {
int giorno;
char mese[4];
int anno;
} Data ;
void stampaData(Data d) {
printf("%d", d.giorno);
• Protezione da operazioni illegali (type checking)
Data d;
int g;
d = g; // illegale! …forse non si voleva scrivere così!*/
– Errori di tipo sono rilevati dal compilatore: non è necessario
eseguire il programma per scoprirli
printf("%d", d.mese);
printf("%d", d.anno);
}
Java
5
Disastro!
6
Le modifiche sono costose
• Il codice scritto da Bruno non funziona più!
• Occorre modificarlo:
• 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
Data d;
…
if (d.giorno == 27)
paga_stipendi();
if (strcmp(d.mese,"Dic"))
paga_tredicesime()
…
Java
Java
• La realizzazione interna (implementazione) delle strutture dati
è una delle parti più soggette a cambiamenti (per maggiore
efficienza, semplificazione codice...)!
7
Java
8
Soluzione
Come usare una Data?
• Il problema può essere risolto disciplinando o
impedendo l'accesso alla realizzazione della struttura
dati.
• Se si impedisce a Bruno l'accesso ai campi della
struttura Data, come può Bruno utilizzare le date di
Alberto?
– Bruno non deve più scrivere: (d.mese == 12)
struct Data {
int giorno;
int mese;
int anno
};
• Il responsabile per Data (Alberto) deve fornire delle
operazioni sufficienti agli utilizzatori o clienti del tipo
Data (Bruno)
Java
9
Funzioni predefinite per Data
Java
10
Uso delle operazioni predefinite
• L’accesso alla struttura dati è fornito unicamente tramite
operazioni predefinite
• Il codice di Bruno è scritto in modo tale da usare solo
le operazioni predefinite:
In C:
Data d;
…
inizializzaData(*d, 14,12,2000);
if (leggi_giorno(d) == 27)
paga_stipendi();
if (leggi_mese(d) == 12)
paga_tredicesime()
…
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
11
Java
12
Modifica struttura dati
Incapsulamento
• 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";
…
}
• Abbiamo INCAPSULATO la struttura dati!
• Ogni modifica alla struttura resta confinata alla
struttura stessa
• Le modifiche sono
– più semplici
– più veloci
– meno costose
• Ma il codice di Bruno non cambia!
Java
13
Tipo di dato astratto (ADT)
Java
14
Progettare l'interfaccia
• Astrazione sui dati che non classifica i dati in base a loro
rappresentazione (IMPLEMENTAZIONE), ma in base a loro
comportamento 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
• 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:
– 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
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 avrebbe
difficoltà a scriverla senza accedere ai campi di una Data.
Java
15
Java
16
ADT in C?
Costrutti per ADT
• C non ha costrutti linguistici diretti per definire ADT (tipo
abstracttypedef).
• Bruno potrebbe accedere direttamente ai campi della struct che
rappresentano la data. Non possiamo impedirglielo.
– Ma con preprocessore, header files, puntatori, prototipi e una certa disciplina
si può separare interfaccia e implementazione.
• 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.
• C inoltre manca di molte altre astrazioni utili per programmazione inthe-large, che si ritrovano invece nei linguaggi orientati agli oggetti
Java
17
Java
Il linguaggio Java
18
Caratteristiche
• Object-oriented (OO)
• Distribuito
• Definito dalla Sun Microsystems nel 1995/96.
Useremo la versione J2SE 1.5 (Java 2 Standard
Edition)
• Esistono anche J2EE (Java 2 Enterprise Edition)
– RMI
• Indipendente dalla piattaforma
– Bytecode e Java Virtual Machine
– costruita sopra J2SE, offre servlets e JSP, EJB…
– per sviluppare applicazioni "server side"
• Sicuro
– Esecuzione in una "sandbox" che garantisce che non si possa
danneggiare l'host
• J2ME (Java 2 Micro Edition)
– per piccoli dispositivi (telefoni, PDA,…)
Java
19
Java
20
Programmazione “in-the-small” e
programmazione “in-the-large”
Quadro d'insieme
• Programmazione “in the small”
– Tipi primitivi (simili al C, con differenze)
– Dichiarazione di variabili
– Strutture di controllo: selezione condizionale, cicli
• 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
• sono identiche a quelle del C: if, switch, while, for...
• 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
21
– Array (differenze col C)
• Programmazione “in the large”
– Classi
– Interfacce
– Packages
– Information Hiding
– Ereditarietà
– Polimorfismo e binding dinamico
Java
22
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
Il concetto di classe
ADT in Java
23
Java
24
Il primo programma Java
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
file: HelloWorld.java
public class HelloWorld {
public static void main(String args[]){
System.out.println(“Hello world!”);
}
}
25
Esempio di classe in Java
Java
26
Il costrutto class
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*);
}
• 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
• class è come struct, ma alcuni campi possono essere funzioni. Dati e
funzioni sono incapsulati. I private sono “invisibili all’esterno”, mentre i
“public” no.
• Definisce proprio un ADT.
• Una nuova classe viene definita nel seguente modo:
<visibilità> class <nome classe> {
<lista di definizioni di attributi, costruttori e metodi>
Java
27
Java
28
Attributi di una classe
Altro esempio
• La struttura dati di una classe è definita dai suoi attributi
• Esempio:
ATTRIBUTI
class Data {
private int giorno;
private int mese;
private int anno;
...
– giorno, mese, anno sono gli attributi di Data
}
Java
class Automobile {
private String colore, marca, modello;
private int cilindrata, numPorte;
private boolean accesa;
}
29
Java
30
Oggetti
Classi e oggetti
• In un programma OO si dichiarano classi per potere
definire degli oggetti
• Un oggetto è un’area di memoria che contiene valori
per ogni attributo definito nella classe (e’ quindi
come un valore di una struct)
• 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 e associare gli oggetti alle variabili
• (oggetti e variabili non sono la stessa cosa...)
nome dell’oggetto
• Tutti gli oggetti della stessa classe hanno la
stessa struttura
nome della classe di cui
l’oggetto è istanza
data1
Data
– Il numero e tipo dei loro attributi di istanza è lo stesso
nome e valore
degli attributi
– Ad esempio, la classe Data definisce tutte le date possibili,
tramite gli attributi giorno, mese, anno.
Java
attributi
31
giorno = 30
mese = 12
anno = 2001
Java
32
Metodi di una classe
Oggetti
• Stato di un oggetto: Ogni oggetto, in ogni istante dell’esecuzione del
programma, è caratterizzato da uno stato
– Lo stato rappresenta la condizione in cui si trova l’oggetto
– Lo stato è definito dai valori delle variabili interne all'oggetto
(attributi)
– Es. lo stato dell’oggetto data1 di tipo Data è definito dal valore degli
attributi giorno, mese, anno
• I metodi sono procedure che
• Comportamento di un oggetto
– Determina come agisce e reagisce un oggetto
– È definito dall’insieme di operazioni che si possono richiamare
sull’oggetto
–“appartengono” agli oggetti (se non si usa la parola chiave
static—vedremo )
–hanno come parametro implicito l’oggetto cui appartengono
(this)
• Un oggetto è pertanto un’entità “viva”, che può essere e
modificata e letta tramite operazioni
Java
33
Definizione di metodi
Java
34
Accesso ad attributi e metodi
• I metodi definiscono il comportamento degli oggetti
appartenenti ad una classe
• Ogni metodo è definito come segue:
• Tramite la "notazione punto"
• Esempio:
Data d;
int x;
...//codice che inizializza d
x = d.leggi_giorno();
<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
• 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
• Un oggetto è detto istanza (o esemplare) della classe che
abbiamo usato come stampo per crearlo
35
– 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
36
Qualche cambiamento...
Oggetti mutabili (e immutabili)
• Cambia la sintassi...
• Lo stato degli oggetti (mutabili) può cambiare nel tempo,
chiamando metodi opportuni
– 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; -– Data d; --
a è una variabile di tipo int
d è una variabile di classe Data
Data
data1.giorno_dopo()
giorno = 31
mese = 12
anno = 2001
• Esistono anche oggetti immutabili (cioè che non possono essere
modificati dopo la loro creazione), come ad es. la classe
predefinita String.
37
Il metodo giorno_dopo()
Java
38
Private e Public
• Per modificare lo stato, il metodo deve potere accedere ai campi
dell’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(){
• Attraverso i metodi "public" di una classe è possibile
vedere qual’è lo stato di un oggetto ...
– Data d;
int x;
...
x = d.leggi_giorno();
//@ ensures (*incrementa la data*)
giorno++;
if (giorno > 31){
giorno = 1; mese++;
if (mese > 12) {
mese = 1; anno++;}}}
• …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.
…
Data d;
…
d.giorno_dopo(); /*modifica lo stato dell’oggetto d*/
Java
data1
Data
giorno = 30
mese = 12
anno = 2001
analogia con le struct del C
Java
data1
39
Java
40
Classi e ADT
• Il costrutto di classe consente di definire tipi di dati
astratti (ADT)
• Un ADT permette di estendere il linguaggio con
nuovi tipi di dato
• Il costrutto di classe è caratteristico dei linguaggi
orientati agli oggetti (OO)
• Caratteristiche principali dei linguaggi OO (ne
vedremo altre)
Programmazione "in the small"
– Incapsulamento delle strutture dati
– Protezione, al fine di impedire l'accesso
all'implementazione (information hiding)
Java
41
Java
Variabili e tipi riferimento
Tipi primitivi e variabili
• Tipi numerici:
–
–
–
–
–
–
byte:
short:
int:
long:
float:
double: 64 bit
• 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:
Dichiarazione di variabili
8 bit
16 bit
32 bit
64 bit
32 bit
byte un_byte;
int
a, b=3, c;
Char c=‘h’, car;
Boolean trovato=false;
–
–
–
–
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...
• Altri tipi:
– boolean:
– char:
42
true false
16 bit, carattere Unicode
• 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
43
Java
44
Dichiarazione e inizializzazione
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
d
3
11
1991
xxx
– 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
giorno
mese
anno
Java
• 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
45
New
Java
Differenze tra dichiarazione e creazione
• 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
Data
data;
data
=
new
Data( );
data
=
new
Data( );
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
46
47
Creato
Creatocon
conlala
prima
primanew.
new.
Data
Data
Java
Creato
Creatocon
conlalaseconda
secondanew.
new.IlIl
riferimento
riferimentoalalprimo
primooggetto
oggetto
Data
Dataèèperso.
perso.
Non
Nonc’è
c’èpiù
piùmodo
mododidiaccedere
accedere
all’oggetto.
all’oggetto.
L’oggetto
L’oggettoverrà
verràdistrutto
distruttodal
dal
garbage
garbagecollector.
collector.
48
Creazione e distruzione degli oggetti
Costruttori
• Se implementazione deve essere private, unico modo per inizializzare
un oggetto è specificare uno o più metodi particolari, chiamati
costruttori
– 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
• La creazione di un oggetto (tramite new) 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
• Un costruttore è un metodo speciale:
49
• Vantaggio: all’allocazione si esegue sempre anche l’inizializzazione,
eliminando una frequente fonte di errori.
Java
50
Costruttori di default
Esempio di costruttore
public class Date {
• Se non si definisce nessun costruttore, il compilatore fornisce il
costruttore di default (senza parametri), che svolge le seguenti
funzioni:
private int month, day, year;
public Date(int d, int m, int y) { // day month year
year = y; month = m; day =d)
– 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
...
}
…
Date d = new Date(3,12,1987);
• Il costruttore di default (senza parametri) viene fornito dal
compilatore a meno che non si definiscano altri costruttori
Î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
51
Java
52
I costruttori: esempio
public class C {
private int i1;
private int i2;
public C() {
i1 = 0; i2 = 0;
}
Assegnamento
• L’operatore di assegnamento “=“, quando applicato a:
– Variabili e espressioni di tipi primitivi: copia il valore.
– Es. int x,y; x=5; y=x;
“omaggio” del compilatore:
non è necessario scriverlo
• In y viene copiato il valore contenuto in x;
}
....
public class Esempio {
public static void main(String args[]) {
C x;
Corretto perchè il compilatore ha inserito
x = new C();
automaticamente il costruttore di default
x = new C(5,7);
}
}
– variabili e espressioni di tipo riferimento: copia il riferimento,
non l’oggetto.
– Es. Data d1, d2;d1=new Data(1,2,2004); d1 = d2;
– In d1 è copiato il riferimento, cioe’ d1 e d2 referenziano (ossia
condividono) lo stesso oggetto.
Sbagliato, non esiste nessun costruttore che prenda due
parametri
Java
53
Java
Es. di sharing
Condivisione (sharing)
• Un oggetto è condiviso tra due variabili se entrambe accedono a
esso
• L'assegnamento di variabili di tipo riferimento genera condivisione
(vedi d1 e d2 nell'esempio precedente)
• Se oggetti condivisi sono modificabili, le modifiche apportate
attraverso una variabile sono visibili anche attraverso l'altra (side
effect)
• Questo di per se’ non e’ un problema, ma può rendere I
programmi difficili da capire.
Java
54
55
definisce riferimento d a una Data, senza inizializzarlo
Data d;
Alloca in memoria, in celle consecutive, attributi di Data.
d1 diventa l’indirizzo della prima cella
Data d1= new Data();
d diventa uguale a d1: l’indirizzo contenuto in d
diventa uguale all’indirizzo contenuto in d1 (diventano
alias, cioè nomi diversi per la stessa area di memoria
d=d1;
anche d.giorno diventa 1, poiché d e d1 sono alias
d1.giorno =1;
d
xxx
d1
xxx
1
..
..
Java
giorno
mese
anno
56
Confronto di uguaglianza
Reference e operatore “== ”
– Metodo equals( ) consente di verificare se due oggetti sono
uguali (nel senso che hanno lo stesso valore dello stato)
•L’operatore di confronto == confronta i valori dei reference.
non gli oggetti!
d
giorno
1
xxx
Data d = new Data(1,12,2001);
mese
12
Data d1= new Data(1,12,2001);
2001 anno
if (d==d1) {
d1
giorno
1
...
yyy
mese
12
false: d e d1 sono riferimenti a oggetti
2001 anno
d=d1;
• 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
diversi (anche se hanno gli stessi valori per gli
attributi) e quindi hanno indirizzi diversi false
d == d1 diventa true: l’indirizzo contenuto in d diventa uguale
all’indirizzo contenuto in d1 (diventano identici)
Java
57
Java
Esempio: allocazione degli oggetti
Stack vs. Heap
• Le variabili consentono di accedere agli oggetti
• Le variabili sono sempre allocate nello stack a run-time
– allocate quando si chiama il sottoprogramma in cui sono
dichiarate
– deallocate quando il sottoprogramma ritorna al chiamante
• Gli oggetti referenziati dalle variabili sono invece
sempre allocati nello heap
i
m
k
y
6
[0, 0, 0]
h
una persona
int i = 6;
int [ ] m = {0, 0, 0};
String k = "abcd";
persona y = new persona();
String h;
h=k;
crescita dello stack
59
Heap
"abcd"
– deallocati automaticamente solo quando non più riferiti da
nessuna variabile
Java
58
Java
60
La visione a "run-time"
i
m
k
y
6
Conseguenze allocazione stack vs. heap
[0, 0, 0]
"abcd"
h
una persona
Dichiarazioni all'interno
di un sottoprogramma
int i = 6;
int [ ] m = {0, 0, 0};
String k = "abcd";
Persona y = new Persona();
String h;
h=k;
• 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() {
1
d xxx
Data d = new Data(1,1,1990);
1
return d;
1990
}
public static void main(String args[]) {
x xxx
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!!!*/
crescita dello stack
Java
61
Riassumendo:
riferimenti e oggetti
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;
}
}
• 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
63
Java
64
Chiamata di metodi
-semantica-
Invocazione dei metodi
1. Vengono valutati i parametri attuali
2. Viene creata area dati ("record di attivazione") sullo
stack
•
•
spazio per i parametri formali (inizializzati col valore degli
attuali)
spazio per le variabili locali
• 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)
3. Esecuzione del corpo
si tratta di puntatori agli oggetti,
tranne che per il caso dei tipi primitivi
Java
65
Passaggio parametri e reference: esempio 1
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) {
Date d1 = new Date(3,2,1984);
Date d2 = new Date(1,1,1990);
Date d1 = new Date(1,1,1990);
d1.copiaIn(d2);
Date.reinizializza (d1);
AlQuando
momento
chiamata:
la della
funzione
termina, d1 e' 31/12/1999
d1
xxx
xxx
quando copiaIn termina d2 è 3/2/1984
d
131
1
12
1990
1999
Java
66
Passaggio parametri e reference: esempio 2
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) {
d
Java
d2
67
xxx
xxx
d1
1
1
1990
Java
yyy
3
2
1984
68
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[]
Dettagli sul linguaggio Java
Java
69
Tipi array:
dichiarazione e inizializzazione
Java
70
Il caso degli array
• Dichiarazione:
• 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:
int[] ai1, ai2;
float[] af1;
double ad[];
Persona[][] ap;
– new <tipo> [<dimensione>]
int[] i=new int[10], j={10,11,12};
float[][] f=new float[10][10];
Persona[] p=new Persona[30];
• Inizializzazione:
int[] ai={1,2,3};
double[][] ad={{1.2, 2.5}, {1.0, 1.5}}
Java
• Se gli elementi non sono di un tipo primitivo, l’operatore “new”
alloca solo lo spazio per i riferimenti
71
Java
72
Array di oggetti: Definizione
A
A
Person[ ]
Array di oggetti: Definizione
person;
Person[ ]
person = new Person[20];
E’
E’definita
definitasolo
sololalavariabile
variabile
person.
person.L’array
L’arrayvero
veroee
proprio
non
esiste
proprio non esiste
person[0] = new Person( );
person
B
B
Ora
Oral’array
l’arrayèèstato
statocreato
creatoma
ma
i idiversi
diversioggetti
oggettididitipo
tipo
Person
non
esistono
ancora.
Person non esistono ancora.
person[0] = new Person( );
person
0
Java
Person[ ]
1
2
3
4
73
16 17 18
19
Java
74
Array di oggetti vs. array di tipi base
Array di oggetti: Definizione
L’istruzione:
person;
person = new Person[20];
C
C
person;
person = new Person[20];
person[0] = new Person( );
Un
Unoggetto
oggettodiditipo
tipopersona
personaèè
stato
statocreato
creatoeeun
unriferimento
riferimento
aatale
taleoggetto
oggettoèèstato
stato
inserito
inseritoininposizione
posizione0.0.
float f[] = new float[10];
crea un oggetto di tipo array di float e alloca spazio per 10 float
f
0 1 2 3 4
5 6 7 8 9
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
person
L’istruzione:
Person p[] = new Person[10];
0
1
2
3
4
16 17 18
crea un oggetto di tipo array di Person e alloca spazio per 10
riferimenti a oggetti di tipo Person
19
f
Non viene allocato
spazio per gli oggetti
veri e propri
Person
Java
75
0
1
Java
2
3
4
5
6
7
8
9
76
Loop generalizzato per collezioni
Esempio per array
• Se abbiamo una collezione C di elementi di tipo T,
possiamo itrerare su di essi scrivendo
for (T x: C) {
int sum (int [ ] a) {
int result = 0;
n indica il generico elemento
for (int n : a)
result += n; dell'arry, NON l'indice!
return result;
}
esegui azioni su x
}
• anche gli array osno collezioni, quindi …
Java
77
Accesso ad attributi e metodi locali
Java
78
Visibilità dei nomi
• 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)
• Esempio
class Automobile {
String colore;
• Le variabili locali ad 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
void dipingi(String col) {colore=col;}
...
}
Java
79
Java
80
this per aggirare mascheramenti
La pseudo-variabile this: esempio
• La pseudo-variabile this contiene un riferimento
all’oggetto corrente e può essere utilizzata per aggirare
eventuali mascheramenti
public 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”);
• class Data {...
public void giorno_dopo(){
//MODIFIES: this
//REQUIRES: this è una data valida
//EFFECTS: incrementa la data
this.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.
• => a.marca diventa “Ford”, a.modello diventa “T4”
Java
81
Java
82
Oggetti mutabili (richiamo...)
this per restituire un reference
• La pseudo-variabile this può essere utilizzata per restituire un riferimento all'oggetto
corrente.
• Lo stato degli oggetti mutabili può cambiare nel tempo, chiamando
metodi opportuni
• public class InsiemeDiInteri {
...
public InsiemeDiInteri inserisci(int i){
…//modifica this inserendovi l’elemento i
return this; //restituisce l‘insieme modificato...
}
….
}
…..
InsiemeDiInteri x,y,z;
….//qui x e y sono inizializzate opportunamente
z = (x.inserisci(2)).unione(y) //utile che inserisci restituisca insieme
Java
data1
data1
Data
Data
giorno = 30
mese = 12
anno = 2001
data1.giorno_dopo()
giorno = 31
mese = 12
anno = 2001
• NB: Esistono alcuni casi in cui gli oggetti sono immutabili (cioè non
possono essere modificati), come ad es. la classe predefinita String
83
Java
84
Oggetti immutabili
La classe predefinita String
• L'oggetto "abcd" (in quanto "String") è immutabile: il
suo stato non cambia
– non esistono operazioni che consentono di modificare lo stato
di un oggetto string
in Java è un tipo riferimento (è definito da una
classe)
• Due regole base:
• String
– 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)
• In generale, invece, gli oggetti sono mutabili:
• (per avere stringhe mutabili si usa StringBuffer)
int [ ] x = {0, 0, 0};
x[0] = 5;
• Per le stringhe c’è operatore di concatenamento +
• Costruttori:
– String()
– String(String s)
–…
•Metodi (pubblici):
–int length() restituisce la lunghezza di una
stringa;
–char charAt(int index) restituisce il char alla
posizione index (il primo ha posizione 0)
–String substring(int beginIndex) (parte da 0)
Java
85
Java
La classe String: esempio d’uso
86
Enumerazioni
•
public class ProvaString {
//OVERVIEW: …
public static void main (String argv[]) {
String a = new String(); //a è reference a stringa vuota
String b = new String("Ciao“); //b è reference a stringa “Ciao”:
//abbreviazione: String b = "Ciao“;
String c = new String(b); //Ora c e' copia di b
String d = b; //d e b sono alias
System.out.println(b + " " + c + " “+ d);
}
}
L’assegnamento d=b e’ assegnamento dei reference! Non si copia l’oggetto!
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 istanzen non se ne possono
costruire altre
•
•
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 costanti
enumerate
– Non c’è bisogno di usare equal per confrontare I valori, basta ==
– Costruttori invocati solo quando vengono costruite le costanti
enum 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;}
};
– Costruttori invocati solo quando vengono costruite le costanti
Java
87
Java
88
• Tutte classi enumerate eredi della classe Enum che offre I seguenti
metodi
// dà la costante enumerata della classe indicata che ha quel nome
static Enum valueOf(Class enumClass, String name)
// dà il nome della costante enumerata
String toString()
– Molto utili nell operazioni di I/O di valori della classe enumerata
Scanner in = new Scanner(System,in);
String str = in.next(); //e.g. se letta stringa “SMALL”...
Size siz = Enum.valueOf(Size, str); //...dà costante Size.SMALL
System.out.println(Size.LARGE.toString()); //stampa “LARGE”
• Ogni classe enumerata ha un metodo static che restituisce un array
contenente tutti i valori della classe
Size[] valori = Size.values;
Java
•
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 kilograms
private final double radius; // in meters
Planet(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();
}
}
89
A partire dal peso di un corpo sulla terra, calcola e stampa il peso su tutti gli altri
pianeti
Java
90
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
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));
}
– Attenzione: Il tipo del valore di restiuito non basta a distinguere due metodi
(motivo: a volte un metodo può essere chiamato solo per i side-effect e
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:
$ 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
Java
•
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
91
Java
92
Overloading dei costruttori: esempio
Overloading: un esempio
class C {
int f() {...}
z
C ref = new C();
int f(int x) {...}
// corretto
ref.f();
//distinguibile
void f(int x) {...}
// errato
ref.f(5); //???
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;
}
x = new C();
y = new C(1);
z = new C(1,4);
}
}
C
y
i1 = 1
x
i2 = 1
C
i1 = 1
i2 = 4
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
Java
93
94
Ulteriore esempio
Argomenti in numero variabile
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;}
}
• In Java 1.5 si possono creare metodi e costruttori
con 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
Java
95
Java
96
Metodi e attributi di classe: vincoli
Metodi e attributi di classe (o “statici”)
• 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:
• Un metodo static può accedere ai soli attributi e
metodi static
<nome classe>.<nome attributo>
• Un metodo convenzionale può accedere
liberamente a metodi e attributi static
• 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 oggetto
della classe
Java
97
Java
98
Visione a run time
Metodi e attributi di classe: esempio
tutte le forme ("shape") vengono visualizzate
su 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); ...}
}
shape1
shape2
...
Shape.setScreen(new Screen()); // corretto
Shape.show(); // errato, show è un metodo normale
Shape s1=newShape(), s2=new Shape();
Screen s=new Screen();
s1.setScreen(s); // corretto, si possono chiamare
// metodi static su oggetti
shape3
// in questo punto s2.screen==s1.screen==s
Java
Allocato
99
Java
100
Tipi riferimento per i tipi primitivi
Attributi costanti
• Tipi primitivi comodi, ma a volte si preferirebbe usarli come riferimento,
per omogeneità
• Es. Java fornisce classi predefinite Integer, Character
• È possibile definire attributi costanti tramite la notazione:
final <definizione di attributo>=<valore>
– 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)
• Esempio
class Automobile {
int colore;
final int BLU=0, GIALLO=1,...;
void dipingi(int colore) {this.colore=colore;}
}
...
Automobile a=new Automobile();
a.BLU=128; // errato
System.out.println(“BLU=“+a.BLU); // corretto
Integer i;
i = new Integer(5);
Integer x = i;
int y = x.intValue();
// qui i vale null!
//i è un rif. a oggetto che contiene 5
// sharing: x e i sono stesso oggetto
// per accedere a valore di x
NB: Java 1.5 ora fornisce “autoboxing...”
Java
101
Java
102
Packages
• Classi (e interfacce, che vedremo tra breve) sono
raggruppate in packages
• Il package raggruppa (incapsula) classi e
interfacce, definendo regole di visibilità
• Se visibile nel package A, un'entità X dichiarata nel
package B viene denotata come B.X
Packages e Information Hiding
– quindi si possono usare liberamente gli stessi nomi in
packages diversi, senza generare confusione
Java
103
Java
104
Information hiding in Java (1)
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
•
– public
• sono visibili a tutti con import
• file deve avere stesso nome
• al più una public class per ogni file
– "friendly":
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
• Classi possono essere:
• sono visibili solo all’interno dello stesso package/compilation
unit
• possono stare in file con altre classi
105
Java
Information hiding (2)
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
106
107
• 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
108
Information hiding (3)
Information hiding (4)
• 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
• E' fortemente consigliato che gli attributi di una classe public
siano 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!
109
Java
Il package java.lang
110
Ereditarietà
• Il package java.lang contiene classi di uso molto
frequente (String, Object, ecc.)
• E’ possibile stabilire una relazione “sottoclasse_di (⊆) fra le classi di un
programma Java
– relaz. d’ordine parziale (riflessiva e transitiva)
• Non è necessario importare le classi appartenenti al
package java.lang prima di utilizzarle
B
public class D extends B {…}
D
• B classe base, o antenato, o padre,
o sovraclasse, …
• D classe derivata, o discendente, o figlio, o erede, o sottoclasse,
…
Java
111
Java
112
La relazione di ereditarietà
Un semplice esempio
• 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
public 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;}
...
}
113
Java
Overriding
114
Gerarchia a più livelli
• 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:
Figure
perimeter
area
ClosedFigure
public class AutomobileElettrica extends Automobile {
...
public void accendi() {// OVERRIDING
….accensione auto elettrica e’ diversa da quella di auto a
benzina… la reimplementiamo
number_of_sides
pixel width
color
scale
rotate
draw
OpenFigure
Ellipse
Polygon
Rectangle
Java
115
Java
116
Esempio: Progetto tradizionale in C
typedef struct …Figura;
Figura
Costruire software estendibile usando ereditarietà
Cerchio
Rettangolo
Figura figure[100];
Triangolo
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”
}
}
Java
117
Es. in versione OO
Estendere progetto tradizionale: arriva il Trapezio
Figura
class Figura
public void
disegna(){…}
typedef struct …Figura;
Figura figure[100];
Cerchio
Rettangolo
Triangolo
//si definisce classe (astratta) Figura, con
metodo (astratto) disegna(), e sue eredi
Rettangolo, Cerchio, Triangolo che
implementano disegna()
Figura figure = new Figura[100];
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
}}
figure[1] = “rettangolo”;
figure[2] = “triangolo”;
figure[3] = “cerchio”;
figure[4] = “trapezio”
Codice già definito per
disegnaTutto deve
cambiare per potere
supportare il nuovo
tipo!!!
class Cerchio
public void
disegna(){…}
classRettangolo
public void
disegna(){…}
class Triangolo
public void
disegna(){…}
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();}
legale in Java: a run-time si decide quale impl. di
disegna() chiamare: quella di Cerchio, di
Rettangolo, o di Triangolo…
Quantità di codice è più o meno la stessa di prima, ma è
meglio organizzato...
Estendibilità: arriva il Trapezio
Figura figure = new Figura[100];
class Figura
public void
disegna(){…}
class Cerchio
public void
disegna(){…}
figure[1] = new Rettangolo();
figure[2] = new Triangolo();
figure[3] = new Cerchio();
figure[4] = new Trapezio();
classRettangolo
public void
disegna(){…}
class Triangolo class Trapezio
public void
public void
disegna(){…}
disegna(){…}
Polimorfismo
…disegnaTutto(figure);
“Chiave” per costruire software estendile
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!!!
Java
Esempio: codice definito per sopraclasse funziona anche con
sottoclasse
Polimorfismo
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
• 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
....
Vediamo perché tutto funziona come ci aspettiamo….
Java
122
123
Java
124
Tipo apparente e tipo effettivo
Esempio
• Oggetti hanno un tipo apparente (“statico”): quello definito
dalla 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 apparente e effettivo
AutomobileElettrica
• In Java, tipo effettivo può essere sottotipo del tipo
apparente
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;
Automobile myCar = new AutomobileElettrica();
il tipo statico di myCar è Automobile
quello dinamico è AutomobileElettrica
Java
125
Java
126
Uso delle classi dell’Esempio: assegnamento
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 quello
apparente
Automobile myCar = new AutomobileElettrica();
• Il compilatore quindi verifica che ogni oggetto venga manipolato
correttamente solo in base al tipo apparente
• La regola precedente pero’ garantisce che a run time non sorgono
errori se invece si opera su un oggetto il cui tipo dinamico è un
sottotipo del tipo statico
Corretto: tipo (apparente) di mycar è
sopratipo di tipo (apparente) di yourCar
myCar
127
Ford
false
modello
accesa
Automobile myCar = new Automobile(“Ford”);
AutomobileElettrica yourCar = new AutomobileElettrica(“El”);
...
myCar = yourCar;
yourCar
Java
xxx
xxx
El
false
Java
true
modello
accesa
128
batterieCariche
Uso delle classi dell’Esempio: assegnamento
Uso delle classi dell’Esempio: assegnamento
Corretto: tipo (apparente) di mycar è
sopratipo del tipo effettivo
scorretto: tipo (apparente) di yourCar non
è sopratipo di tipo (apparente) di myCar
Automobile myCar = new Automobile();
AutomobileElettrica yourCar;
...
yourCar = 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
Automobile myCar = new AutomobileElettrica();
129
Uso delle classi dell’Esempio: assegnamento
Java
130
Uso delle classi dell’Esempio: chiamata di un metodo
Scorretto: tipo (apparente) di yourCar non
è sopratipo del tipo del costruttore
Automobile myCar = new AutomobileElettrica();
...
myCar.puoPartire(); //ok, chiama metodo di Automobile
myCar.accendi(); //ok, chiama metodo di AutomobileElettrica
myCar.ricarica(); //KO, ricarica non è metodo di Automobile
AutomobileElettrica yourCar = new AutomobileElettrica ();
yourCar.ricarica(); //OK, chiama metodo di AutomobileElettrica
AutomobileElettrica yourCar = new Automobile ();
Java
131
Java
132
Esempio
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 metodo
attivato è dinamico, dipende dal tipo attuale
dell'oggetto. Dispatching è la tecnica usata per
realizzare binding dinamico.
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 Automobile
a2.accendi(); a run time si chiama implementazione di
AutomobileElettrica
partenza(a2); solo a run time si può conoscere il tipo effettivo
public static int partenza(Automobile a) {
a.accendi();//funziona anche con AutomobileElettrica
…}
Java
133
Java
Dispatching (binding dinamico)
Implementazione dispatching
• Esempio:
static void partenza (Automobile p) {
//accende p e la fa partire
p.accendi();
...
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
puntatore
al codice
a1
a2
accendi
– varie tecniche implementative: per es. ogni oggetto può
contenere un puntatore al codice dei propri metodi
Java
134
puntatore
al codice
135
Java
136
Overloading e overriding
Regola per chiamata metodi
• Binding dinamico non va confuso con overloading
class Punto2D{
public float distanza(Punto2D p){…}
}
class Punto3D extends Punto2D {
public float distanza(Punto 3D p){…}//OVERLOADING!!!
}
• Il metodo distanza di Punto3D ha una segnatura diversa da
quella di distanza dichiarato in Punto2D: NON è overriding Î
non si applica binding dinamico
• Punto2D p = new Punto3D();
• p.distanza(p); //chiama Punto2D.distanza(Punto2d)!!!
Java
137
• 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 P del parametro attuale p e al tipo statico X di x.
• 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 run
time il metodo “più vicino” fra i metodi che hanno il prototipo
Y.m(P’) stabilito staticamente.
Java
138
Esempio
class Punto2D{public float distanza(Punto 2D){…}…}
class Punto3D extends Punto2D {public float distanza(Punto 3D){…}}
Punto2D p1,p2;
Punto3D p3;
p1 = new Punto2D(3,7);
p2 = new Punto3D(3,7, 4);
System.out.println(p1.distanza(p2));
System.out.println(p2.distanza(p1));
p3 = new Punto3D(6,7, 5);
System.out.println(p2.distanza(p3));
System.out.println(p3.distanza(p1));
System.out.println(p1.distanza(p3));
Punto3D p4 = new Punto3D(6,1, 5);
System.out.println(p3.distanza(p4));
Classi e tipi
metodo di Punto2D
Punto2D
Punto2D
Punto2D
Punto2D
Punto3D
Java
139
Java
140
Possibili errori di tipo in un linguaggio
Tipizzazione forte
• Se il compilatore può garantire che NON sorgano errori
di 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
• Assegnamenti tra oggetti di tipo incompatibile
• Chiamate di metodi incompatibili (numero e tipo
dei parametri)
Java
141
Java
Ancora sui tipi in Java
142
Gerarchia di tipi
• Rispetto a C, C++:
– viene fatta automatica garbage collection
• oggetti accessibili via riferimento sono automaticamente
deallocati quando non più riferiti
ciò evita il pericolo di generare dangling references (riferimenti
ad aree di memoria deallocata)
– viene fatto controllo automatico a run time che gli indici di un
array non escano dai limiti
• 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)
Java garantisce che ciò non
comprometta la type safety
(vedremo come)
• il tipo dell'oggetto attualmente assegnato
Java
143
Java
144
Tipo statico e dinamico
• Il compilatore verifica che ogni oggetto venga
manipolato correttamente in base al tipo statico
• Il linguaggio garantisce che a run time non sorgono
errori se invece si opera su un oggetto il cui tipo
dinamico è un sottotipo del tipo statico
Dettagli su ereditarietà in Java
Java
145
Accesso ai membri private
146
Overriding e la pseudo variabile super
• Le sottoclassi non possono accedere agli attributi (e
metodi) private delle sopraclassi!
• è sbagliato scrivere:
• 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>)
public void accendi() {
if(batterieCariche) accesa=true;
...;}
– Esempio:
public class AutomobileElettrica extends Automobile {
...
public void accendi() {// OVERRIDING
if(batterieCariche) super.accendi();
else System.out.println("Batterie scariche");}
}
perché accesa è private nella sovraclasse!
Java
Java
147
Java
148
Accesso ed ereditarietà
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:
• 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
super(<lista di par. attuali>)
posta come prima istruzione del costruttore
Se 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!)
– 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
– In AutomobileElettrica:
149
public AutomobileElettrica(String modello) {
super(modello); //qui inizializza modello e accesa
batterieCariche=false;
}
Java
La classe Object
150
Equals
• 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();
• 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
151
Java
152
toString
clone()
public String toString ( )
• Restituisce una rappresentazione testuale dell’oggetto
• Implementazione fornita da Object:
• Il metodo clone restituisce una copia dell'oggetto, nello
stesso stato
– una stringa che mostra il nome del tipo seguito da una
rappresentazione testuale del valore dell’oggetto
– 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)
– Se si vuole fare una copia "completa" dell'oggetto, il metodo
clone va ridefinito
• la clone fornita da Object fa una "copia superficiale"
• se un attributo è un riferimento, viene copiato il riferimento!!!
Java
153
Java
154
Classi e metodi astratti
Classi e information hiding
Attributi e metodi di una classe
• se non dico nulla sono visibili all'interno del package: chiamato
informalmente “friendly”
• se no, possono essere:
– public
• visibili a tutti
– protected
• visibili all'interno del package
• visibili alle sottoclassi anche se esterne al package
• 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
• ...ci ritorneremo!
– private
• visibili solo all’interno della stessa classe
Java
155
Java
156
Classi e metodi final
Classi e metodi astratti: esempio
• Se vogliamo impedire che sia possibile creare
sottoclassi di una certa classe la definiremo final
abstract class Shape {
static Screen screen;
Shape(Screen s) {screen=s;}
abstract void show();
}
class Circle extends Shape {
void show() {
...
}
}
...
Shape s=new Shape(); // errato
Circle c=new Circle(); // corretto
Java
• 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
}
157
I limiti dell’ereditarietà semplice
Java
158
La soluzione di Java
• L’ereditarietà semplice non permette la descrizione di
numerose situazioni reali
• Esempio:
• Distingue tra una gerarchia di ereditarietà (semplice)
ed una gerarchia di implementazione (multipla) …
• … introducendo il costrutto interface
– Supponiamo di avere una classe Giocattolo ed una classe
Automobile. In assenza di ereditarietà multipla non posso
definire la classe AutomobileGiocattolo
Java
159
Java
160
Interfacce
Attributi costanti
• Una interfaccia è come una classe che può avere solo
attributi costanti e i cui metodi sono tutti pubblici ed
astratti
• Sintassi:
• Implicitamente, gli attributi dichiarati in una interfaccia
sono
– visibili alla classe che la implementa
– immodificabili (static final)
interface <nome> {
<lista di definizione di attributi costanti e
metodi privi di corpo>
}
interface scalable {
int SMALL=0,MEDIUM=1,BIG=2; //static e final
void setScale(int SIZE);
}
Java
161
Java
162
Interfacce ed ereditarietà
La gerarchia di implementazione
• Una interfaccia può ereditare da una o più interfacce
• Sintassi:
interface <nome> extends <nome1>,..,<nomen> {
...
}
• 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
163
Java
164
Promozioni
Conversioni automatiche di tipo
Java
byte
short
int
long
->
->
->
->
short, int, long, float, double
int, long, float, double
long, float, double
float or double
float
char
->
->
double
int, long, float, double
165
Java
Casting in generale
Conversioni forzate: casting
• È possibile forzare esplicitamente la conversione da
un tipo riferimento T ad un sottotipo T1 purché:
•È possibile forzare una conversione di tipo
attraverso l’operatore di casting:
– Il tipo dinamico dell’espressione che convertiamo sia un
sottotipo di T1
(<tipo>)<espressione>
•Tra tipi primitivi sono consentite le seguenti
conversioni forzate (quando possibile e con
perdita di informazione)
short
char
int
long
float
double
byte
->
->
->
->
->
->
->
byte,
byte,
byte,
byte,
byte,
byte,
char
char
short
short,
short,
short,
short,
Java
166
• 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)
char
char, int
char, int, long
char, int, long, float
167
Java
168
instanceof
Esempio: instanceof e ridefinizione di equals
• Per evitare errori runtime e stabilire qual’è il tipo
effettivo 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
169
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
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
170
• Per gli arrayList non c’è la comoda notazione a[i] utilizzabile per gli
array, 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 Joe
team.set(0, new Person(“Mary”,...));
//sostituisce Mary a Bob
• ArrayList sono contenitori “estendibili” e “accorciabili” dinamicamente
• NB ArrayList sono implementati come array di puntatori => metodo add
allunga di 1 la (parte utilizzata del) l’array
– 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)
– Metodi add(indice, oggetto) e remove(indice) aggiungono e tolgono un
elemento nella posizione indicata, alterando la lunghezza dell’ArrayList
team.add(1, new Person(“Sue”,...));
//ora ci sono Mary, Sue, Bob
team.remove(0); // rimuove Mary, ora ci sono Sue e Bob
ArrayList <Person> team = new ArrayList<Person>();
– crea ArrayList privo di elementi e anche di “posizioni” per memorizzarli
– NB add e remove comportano “traslazione” di segmenti dell’ArrayList: sono
operazioni “costose” (costo lineare...)
– ATTENZIONE: metodo set NON deve essere usato per inserire un elemento
in una posizione che non c’è
team.set(4, new Person(“Jack”,...)); // scorretto
• Un ArrayList può essere esteso col metodo add che aggiunge
elementi in fondo, oltre a quelli presenti
team.add(new Person(“Bob”,...));
team.add(new Person(“Joe”,...));
– ora team.size() vale 2
Java
ma solo per sostituire un oggetto già presente in quella posizione
171
Java
172
• ArrayList sono contenitori => si possono scandire gli
elementi usando ciclo for-each
for(Person p: team){
//fa qualcosa con la persona p
}
ArrayList, wrappers e autoboxing
• Gli arraylist (come tutti gli altri contenitori) possono
contenere solo oggetti, NON valori di tipi primitivi
– per memorizzare valori primitivi bisogna includerli in oggetti
delle classi wrapper
è equivalente al tradizionale for
ArrayList<Integer> intList = newArrayList<Integer>();
intList.add(7);
for(int i=0; i<team.size(); i++){
Person p = team.get(i);
//fa qualcosa con la persona p
}
– viene accettato perchè tradotto (dal compilatore) in
intList.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 aggiunto
dal compilatore che produce
int n = intList.get(3).intValue();
Java
173
Vector (Java<1.5)
174
I/O formattato
• Coi Vector (nelle versioni precedenti di Java) si
possono memorizzare solo oggetti Object, quindi in
aggiunta occorre anche un casting prima di effettura
un “unwrap”
Vector myVector = new Vector ();
myVector.add(new Integer(5));
int n = ((Integer)myVector.get(0)).intValue();
Java
Java
• 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); */
...
175
Java
176