Il linguaggio Java
e la progettazione di software
object-oriented
Java
1
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
2
Codice C di Alberto
Codice C di Bruno
•La manipolazione dei dati
avviene con accesso diretto alla
rappresentazione del tipo:
typedef struct {
int giorno;
int mese;
int anno;
} Data;
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
3
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
4
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
5
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
6
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
7
Come usare una Data?
• Se si impedisce a Bruno l'accesso ai campi della
struttura Data, come può Bruno utilizzare le date di
Alberto?
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
8
Funzioni predefinite per Data
• L’accesso alla struttura dati è fornito unicamente tramite
operazioni predefinite
In 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
9
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
10
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
11
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
12
Tipo di dato astratto (ADT)
• 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
– 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
13
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 avrebbe
difficoltà a scriverla senza accedere ai campi di una Data.
Java
14
ADT in C?
• 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.
• C inoltre manca di molte altre astrazioni utili per programmazione inthe-large, che si ritrovano invece nei linguaggi orientati agli oggetti
Java
15
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
16
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
17
Caratteristiche
• Object-oriented (OO)
• Distribuito
– RMI
• Indipendente dalla piattaforma
– Bytecode e Java Virtual Machine
• Sicuro
– Esecuzione in una "sandbox" che garantisce che non si possa
dannegiare l'host
Java
18
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
19
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
20
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
21
Un’anticipazione:
il concetto di classe
ADT in Java
Java
22
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
23
Il primo programma Java
file: HelloWorld.java
public class HelloWorld {
public static void main(String args[]){
System.out.println(“Hello world!”);
}
}
Java
24
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
25
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
26
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
27
Attributi di una classe
• La struttura dati di una classe è definita dai suoi attributi
Java
ATTRIBUTI
class Data {
private int giorno;
private int mese;
private int anno;
...
– giorno, mese, anno sono gli attributi di Data
28
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 attributi
giorno, mese, anno
nome dell’oggetto
nome della classe di cui
l’oggetto è istanza
data1
Data
nome e valore
degli attributi
giorno = 30
mese = 12
anno = 2001
Java
29
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
30
Metodi di una classe
M E T O D I
• 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(){...};
...
}
Java
31
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
32
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
33
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; -– Data d; --
analogia con le struct del C
a è una variabile di tipo int
d è una variabile di classe Data
Java
34
Oggetti mutabilii
• Lo stato degli oggetti (mutabili) può cambiare nel tempo,
chiamando metodi opportuni
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
Java
35
Il metodo giorno_dopo()
• 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(){
//@ 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
36
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
37
Programmazione "in the small"
Java
38
Tipi primitivi e variabili
• Tipi numerici:
–
–
–
–
–
–
byte:
short:
int:
long:
float:
double: 64 bit
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;
• Altri tipi:
– boolean:
– char:
true false
16 bit, carattere Unicode
Java
39
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
40
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
Java
giorno
mese
anno
41
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
42
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
43
Differenze tra dichiarazione e creazione
Data
data;
data
=
new
Data( );
data
=
new
Data( );
data
Creato
Creatocon
conlala
prima
primanew.
new.
Data
Data
Java
Creato
Creatocon
conlalaseconda
secondanew.
new.IlIl
riferimento
riferimentoalalprimo
primooggetto
oggetto
Data
è
perso.
Data è perso.
Non
Nonc’è
c’èpiù
piùmodo
mododidiaccedere
accedere
all’oggetto.
all’oggetto.
L’oggetto
L’oggettoverrà
verràdistrutto
distruttodal
dal
garbage
collector.
garbage collector.
44
La visione a "run-time"
i
m
k
y
6
[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;
crescita dello stack
Java
45
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 apportate
attraverso una variabile sono visibili anche attraverso l'altra (side
effect)
Java
46
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);
d xxx
return d;
}
public static void main(String args[]) {
Data x = foo();
x xxx
...
1
1
1990
/*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!!!*/
Java
47
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
48
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
49
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
50
Array di oggetti: Definizione
A
A
Person[ ]
person;
person = new Person[20];
person[0] = new Person( );
E’
E’definita
definitasolo
sololalavariabile
variabile
person.
L’array
vero
person. L’array veroee
proprio
proprionon
nonesiste
esiste
person
Java
51
Array di oggetti: Definizione
Person[ ]
B
B
person;
person = new Person[20];
person[0] = new Person( );
Ora
Oral’array
l’arrayèèstato
statocreato
creatoma
ma
i idiversi
oggetti
di
tipo
diversi oggetti di tipo
Person
Personnon
nonesistono
esistonoancora.
ancora.
person
0
1
2
3
4
16 17 18
Java
19
52
Array di oggetti: Definizione
Person[ ]
person;
person = new Person[20];
C
C
person[0] = new Person( );
Un
Unoggetto
oggettodiditipo
tipopersona
personaèè
stato
creato
e
un
riferimento
stato creato e un riferimento
aatale
taleoggetto
oggettoèèstato
stato
inserito
inseritoininposizione
posizione0.0.
person
0
1
2
3
4
16 17 18
19
Person
Java
53
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
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
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
f
Non viene allocato
spazio per gli oggetti
veri e propri
0
1
Java
2
3
4
5
6
7
8
9
54
Loop generalizzato per collezioni
• Se abbiamo una collezione C di elementi di tipo T,
possiamo itrerare su di essi scrivendo
for (T x: C) {
esegui azioni su x
}
• anche gli array sono collezioni, quindi …
Java
55
Esempio per array
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;
}
Java
56
I concetti fondamentali per la programmazione “in the large”
•
•
•
•
•
•
•
Classi
Metodi
Interfacce
Information Hiding
Ereditarietà
Polimorfismo e binding dinamico
Packages
Java
57
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
• Per ottenere un nuovo tipo di dato bisogna
definire:
– l’insieme dei possibili valori
– le operazioni possibili sugli oggetti del tipo
Java
58
Linguaggi orientati agli oggetti
• Il costrutto di classe è caratteristico dei linguaggi
orientati agli oggetti (OO)
• Caratteristiche principali (ne vedremo altre)
– Incapsulamento delle strutture dati
– Protezione, al fine di impedire l'accesso all'implementazione
(information hiding)
Java
59
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;
}
Java
attributi
60
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
61
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
62
Chiamata di metodi
-semantica-
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
3. Esecuzione del corpo
si tratta di puntatori agli oggetti,
tranne che per il caso dei tipi primitivi
Java
63
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
64
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) {
Date d1 = new Date(1,1,1990);
Date.reinizializza (d1);
AlQuando
momento
chiamata:
la della
funzione
termina, d1 e' 31/12/1999
d
d1
xxx
xxx
131
1
12
1990
1999
Java
65
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) {
Date d1 = new Date(3,2,1984);
Date d2 = new Date(1,1,1990);
d1.copiaIn(d2);
la della
funzione
termina, d2 e' 3/2/1984
AlQuando
momento
chiamata:
d
d2
xxx
xxx
13
21
1990
1984
Java
d1
yyy
3
2
1984
66
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)
• Esempio
class Automobile {
String colore;
void dipingi(String col) {colore=col;}
...
}
Java
67
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
68
this per aggirare mascheramenti
• 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”);
• => a.marca diventa “Ford”, a.modello diventa “T4”
Java
69
La pseudo-variabile this: esempio
• 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.
Java
70
this per restituire un reference
• La pseudo-variabile this può essere utilizzata per restituire un riferimento all'oggetto
corrente.
• 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
71
Oggetti mutabili (richiamo...)
• Lo stato degli oggetti mutabili può cambiare nel tempo, chiamando
metodi opportuni
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
Java
72
Oggetti immutabili
• 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 generale, invece, gli oggetti sono mutabili:
int [ ] x = {0, 0, 0};
x[0] = 5;
Java
73
La classe predefinita 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)
• (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 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
74
La classe String: esempio d’uso
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!
Java
75
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
76
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-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:
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
77
Overloading: un esempio
class C {
int f() {...}
C ref = new C();
int f(int x) {...}
// corretto
ref.f();
//distinguibile
void f(int x) {...}
// errato
ref.f(5); //???
}
Java
78
Argomenti in numero variabile
• 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
79
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
80
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
81
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
82
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
83
I costruttori: esempio
public class C {
private int i1;
private int i2;
public C() {
i1 = 0; i2 = 0;
}
“omaggio” del compilatore:
non è necessario scriverlo
}
....
public class Esempio {
public static void main(String args[]) {
C x;
Corretto perchè il compilatore ha inserito
x = new C();
x = new C(5,7);
automaticamente il costruttore di default
}
}
Sbagliato, non esiste nessun costruttore che prenda due
parametri
Java
84
Molti costruttori: esempio
z
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);
}
}
y
C
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
85
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
86
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 oggetto
della classe
Java
87
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
88
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); ...}
}
...
Shape.setScreen(new Screen()); // corretto
Shape.show(); // errato, show è un metodo normale
Shape 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
Java
89
Visione a run time
shape1
shape2
shape3
Allocato
Java
90
Attributi costanti
• È possibile definire attributi costanti tramite la notazione:
final <definizione di attributo>=<valore>
• 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
Java
91
Ritorniamo al concetto di sharing
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
92
Reference e operatore “== ”
•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;
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
93
Confronto di uguaglianza
– Metodo equals( ) consente di verificare se due oggetti sono
uguali (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
94
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
95
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;
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
96
Packages e Information Hiding
Java
97
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
– quindi si possono usare liberamente gli stessi nomi in
packages diversi, senza generare confusione
Java
98
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
99
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
100
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
101
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
102
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
103
Information hiding (4)
• 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!
Java
104
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
105
Ereditarietà
• E’ possibile stabilire una relazione “sottoclasse_di (⊆) fra le classi di un
programma Java
– relaz. d’ordine parziale (riflessiva e transitiva)
B
public class D extends B {…}
D
• B classe base, o antenato, o padre,
o sovraclasse, sopraclasse, superclasse …
• D classe derivata, o discendente, o figlio, o erede, o sottoclasse,
…
Java
106
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
107
Un semplice esempio
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;}
...
}
Java
108
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
109
Gerarchia a più livelli
Figure
perimeter
area
ClosedFigure
number_of_sides
pixel width
color
scale
rotate
draw
OpenFigure
Ellipse
Polygon
Rectangle
Java
110
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
111
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
112
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
113
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 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!)
– In AutomobileElettrica:
public AutomobileElettrica(String modello) {
super(modello); //qui inizializza modello e accesa
batterieCariche=false;
}
Java
114
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
115
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
116
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
117
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 metodo
clone va ridefinito
• la clone fornita da Object fa una "copia superficiale"
• se un attributo è un riferimento, viene copiato il riferimento!
Java
118
Costruire software estendibile usando ereditarietà
Java
119
Esempio: Progetto tradizionale in C
typedef struct …Figura;
Figura
Cerchio
Rettangolo
Figura figure[100];
Triangolo
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”
}
}
figure[1] = “rettangolo”;
figure[2] = “triangolo”;
figure[3] = “cerchio”;
Estendere progetto tradizionale: arriva il Trapezio
Figura
typedef struct …Figura;
Figura figure[100];
Cerchio
Rettangolo
Triangolo
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!!!
Es. in versione OO
//si definisce classe (astratta) Figura, con
metodo (astratto) disegna(), e sue eredi
Rettangolo, Cerchio, Triangolo che
implementano disegna()
class Figura
public void
disegna(){…}
class Cerchio
public void
disegna(){…}
classRettangolo
public void
disegna(){…}
Figura figure = new Figura[100];
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(){…}
…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!!!
Polimorfismo
“Chiave” per costruire software estendile
Java
124
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
125
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
126
Tipo apparente e tipo effettivo
• 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 effettivo AutomobileElettrica
• In Java, tipo effettivo può essere sottotipo del tipo
apparente
Automobile myCar = new AutomobileElettrica();
Java
127
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 è Automobile
quello dinamico è AutomobileElettrica
Java
128
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 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
129
Uso delle classi dell’Esempio: assegnamento
Corretto: tipo (apparente) di mycar è
sopratipo di tipo (apparente) di yourCar
myCar
xxx
Ford
false
modello
accesa
Automobile myCar = new Automobile(“Ford”);
AutomobileElettrica yourCar = new AutomobileElettrica(“El”);
...
myCar = yourCar;
yourCar
xxx
El
false
Java
true
modello
accesa
130
batterieCariche
Uso delle classi dell’Esempio: assegnamento
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
131
Uso delle classi dell’Esempio: assegnamento
Corretto: tipo (apparente) di mycar è
sopratipo del tipo effettivo
Automobile myCar = new AutomobileElettrica();
Java
132
Uso delle classi dell’Esempio: assegnamento
Scorretto: tipo (apparente) di yourCar non
è sopratipo del tipo del costruttore
AutomobileElettrica yourCar = new Automobile ();
Java
133
Uso delle classi dell’Esempio: chiamata di un metodo
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
Java
134
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.
Java
135
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 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
136
Dispatching (binding dinamico)
• Esempio:
static void partenza (Automobile p) {
//accende p e la fa partire
p.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
137
Implementazione dispatching
accendi
puntatore
al codice
a1
a2
accendi
puntatore
al codice
Java
138
Overloading e overriding
• Binding dinamico non va confuso con overloading
class 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 è overriding Î
non si applica binding dinamico
• Punto2D p = new Punto3D();
• p.distanza(p); //chiama Punto2D.distanza(Punto2D)!!!
Java
139
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 run
time il metodo “più vicino” fra i metodi che hanno il prototipo
Y.m(P’) stabilito staticamente.
Java
140
Esempio
class 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));
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));
metodo di Punto2D
Punto2D
Punto2D tipo statico di p2 è Punto2D
Punto2D tipo statico di p3 è Punto3D
e tipo statico di p1 è Punto2D Î
scelto distanza(Punto2D)
Punto2D tipo statico di p1 è Punto2D Î
scelto distanza(Punto2D)
tipo statico di p3 è Punto3D
e tipo statico di p4 è Punto3D Î
scelto distanza(Punto3D)
Java
141
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
142
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(); // errato
Circle c=new Circle(); // corretto
Java
143
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
144
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
145
La soluzione di Java
• Distingue tra una gerarchia di ereditarietà (semplice)
ed una gerarchia di implementazione (multipla) …
• … introducendo il costrutto interface
Java
146
Interfacce
• Una interfaccia è come una classe che può avere solo
attributi 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
147
Attributi costanti
• Implicitamente, gli attributi dichiarati in una interfaccia
sono
– 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
148
Interfacce ed ereditarietà
• Una interfaccia può ereditare da una o più interfacce
• Sintassi:
interface <nome> extends <nome1>,..,<nomen> {
...
}
Java
149
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
150
Classi e tipi
Java
151
Possibili errori di tipo in un linguaggio
• Assegnamenti tra oggetti di tipo incompatibile
• Chiamate di metodi incompatibili (numero e tipo
dei parametri)
Java
152
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
Java
153
Ancora sui tipi in Java
• 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
Java
154
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
Java garantisce che ciò non
comprometta la type safety
(vedremo come)
– tipo statico
• il tipo dichiarato
– tipo dinamico (o attuale)
• il tipo dell'oggetto attualmente assegnato
Java
155
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
Java
156
Conversioni automatiche di tipo
Java
157
Promozioni
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
Java
158
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
char
int
long
float
double
byte
->
->
->
->
->
->
->
byte,
byte,
byte,
byte,
byte,
byte,
char
char
short
short,
short,
short,
short,
Java
char
char, int
char, int, long
char, int, long, float
159
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
160
instanceof
• 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
161
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
162
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 aggiunge
elementi in fondo, oltre a quelli presenti
team.add(new Person(“Bob”,...));
team.add(new Person(“Joe”,...));
– ora team.size() vale 2
Java
163
• 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
• 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’ArrayList
team.add(1, new Person(“Sue”,...));
//ora ci sono Mary, Sue, Joe
team.remove(0); // rimuove Mary, ora ci sono Sue e Joe
– 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
ma solo per sostituire un oggetto già presente in quella posizione
Java
164
• ArrayList sono contenitori => si possono scandire gli
elementi usando ciclo for-each
for(Person p: team){
//fa qualcosa con la persona p
}
è equivalente al tradizionale for
for(int i=0; i<team.size(); i++){
Person p = team.get(i);
//fa qualcosa con la persona p
}
Java
165
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
ArrayList<Integer> intList = newArrayList<Integer>();
intList.add(7);
– 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
166
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 effettuare
un “unwrap”
Vector myVector = new Vector ();
myVector.add(new Integer(5));
int n = ((Integer)myVector.get(0)).intValue();
Java
167
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
168
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 possono
costruire 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 costanti
enumerate
– 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;}
};
Java
169
• 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
170
•
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();
}
}
Java
171
•
A partire dal peso di un corpo sulla terra, calcola e stampa il peso su tutti gli altri
pianeti
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
Java
172