H Toulouze / Emergences mai 20031 SECAL La communication de crise.
18 novembre 20031 I nomi in Java F. Bombi 18 novembre 2003.
-
Upload
nazario-giglio -
Category
Documents
-
view
219 -
download
0
Transcript of 18 novembre 20031 I nomi in Java F. Bombi 18 novembre 2003.
18 novembre 2003 1
I nomi in JavaI nomi in Java
F. Bombi
18 novembre 2003
18 novembre 2003
2
Le variabiliLe variabili
Una variabile è una posizione in memoria alla quale è associato un determinato tipo che può essere o un tipo primitivo o un riferimento
Una variabile ha sempre un valore compatibile con il suo tipo
Il valore di una variabile può essere modificato da un’assegnazione oppure da un operatore di incremento (++) o decremento (--)
18 novembre 2003
3
I 7 tipi di variabiliI 7 tipi di variabili
Variabile di classe: un campo di una classe con l’attributo static
Variabile di esemplare: un campo di una classe senza l’attributo static
Componenti di un array: sono variabili senza nome che vengono create quando si crea un array destinate a contenere i singoli elementi dell’array
Parametro di un metodo: nome di una variabile che sarà inizializzata con il valore dell’argomento passato al metodo
Parametro di un costruttore: come per un metodo Parametro di un gestore di eccezione Variabile locale: variabile dichiarata all’interno di un blocco
18 novembre 2003
4
Variabile di classeVariabile di classe
Una variabile di classe viene creata al momento in cui la classe viene caricata nella memoria della macchina virtuale e in assenza di indicazione contraria viene inizializzata a 0, false o null
Di una variabile di classe esiste un solo esemplare condiviso da tutti gli oggetti della classe
L’uso di variabili di classe è limitato a casi molto specifici ad esempio per costanti simboliche condivise oppure per contare quanti esemplari di una classe sono stati creati o per segnalare ad altri esemplari di una classe che si è invocato un metodo
class A{ static int vs; public A () {vs++;} …}…A uno = new A();…A due = new A();…System.out.println(A.vs);
18 novembre 2003
5
Variabili di esemplareVariabili di esemplare
Le variabili di esemplare (instance variable) rappresentano il caso più comune di campo di una classe
Un nuova variabile di esemplare viene creata ogni volta che si crea un esemplare della classe che la contiene, in assenza di indicazione contraria, le variabili di esemplare sono sempre inizializzate a 0, false o null
Un variabile di esemplare cessa di esistere quando l’oggetto che la contiene non è più indirizzato da un riferimento (lo spazio di memoria è a questo punto soggetto a garbage collection)
18 novembre 2003
6
Componenti di un arrayComponenti di un array
Le componenti di un array sono variabile senza nome che vengono create al momento della creazione dell’array.
Sono inizializzati a 00, falsefalse o nullnull
Fare attenzione che se si crea un array di oggetti la creazione dell’array crea solo i riferimenti agli oggetti (inizializzati a null) e non gli oggetti che dovranno essere esplicitamente creati uno per uno
class Coppia{ int a; int b;}…Coppia[] v = new Coppia[4];v[0].a = 25; // null pointer
class Coppia{ int a; int b;}…Coppia[] v = new Coppia[4];for(int i=0;i<4;i++) v[i] = new Coppia();v[0].a = 25; // OK
18 novembre 2003
7
I parametriI parametri
Un parametro attribuisce un nome all’interno di un metodo all’argomento con il quale il metodo viene invocato
Un parametro, analogamente ad una variabile locale, viene creato al momento dell’invocazione del metodo e cessa di esistere quando si conclude il blocco che costituisce il corpo del metodo
Un parametro viene inizializzato con il valore dell’argomento usato al momento della chiamata del metodo
Java di conseguenza utilizza sempre e solo il passaggio dei parametri per valore
class A{ void m(int i) { int locale; locale = i*i; }} …
A x = new A();int k = 25; x.m(k);x.m(3);
parametro
argomentoi = k = 25
18 novembre 2003
8
static void scambia (int x, int y) { int tmp = x; x = y; y = tmp; }
static void scambia (Integer x, Integer y) { Integer tmp = x; x = y; y = tmp; }
static void scambia (MioInt x, MioInt y) { int tmp = x.valore; x.valore = y.valore; y.valore = tmp; }}class MioInt{ int valore; public String toString() { return Integer.toString(valore); }}
// Il passaggio dei parametri in Java
public class Param{ public static void main (String[] arg) { int i = 1; int j = 2; System.out.println("Prima: i= " + i + " j= " + j); scambia(i, j); System.out.println("Dopo1: i= " + i + " j= " + j); Integer ii = new Integer(i); Integer jj = new Integer(j); scambia(ii, jj); System.out.println("Dopo2: i= " + ii + " j= " + jj); MioInt iii = new MioInt(); iii.valore = i; MioInt jjj = new MioInt(); jjj.valore = j; scambia(iii, jjj); System.out.println("Dopo3: i= " + iii + " j= " + jjj); }
Il passaggio dei parametri per valore è unidirezionaleIl passaggio dei parametri per valore è unidirezionale
Prima: i= 1 j= 2Dopo1: i= 1 j= 2Dopo2: i= 1 j= 2Dopo3: i= 2 j= 1
18 novembre 2003
9
int i = 1;int j = 2;
1i
2j
scambia(i, j); static void scambia (int x, int y) { int tmp = x; x = y; y = tmp; }
?x
?y
inizializza?
tmp11
21
2
al ritorno del metodo scambia le variabilii e j sono immutate
18 novembre 2003
10
Integer ii = new Integer(1);Integer jj = new Integer(2);
ii
jj
scambia(ii,jj);
inizializzax
y
al ritorno del metodo scambia i riferimentiii e jj sono immutati
1
2
static void scambia (Integer x, Integer y) { Integer tmp = x; x = y; y = tmp; }
tmp
18 novembre 2003
11
Valore?
jjj
Valore?
iii
MioInt iii = new MioInt(); iii.valore = 1;MioInt jjj = new MioInt(); jjj.valore = 2;
scambia(iii, jjj);
al ritorno del metodo scambia i riferimenti
iii e jjj non sono cambiatisono però stati scambiati i campi
inizializza
x
y1
2
tmp
static void scambia (MioInt x, MioInt y) { int tmp = x.valore; x.valore = y.valore; y.valore = tmp; }
1
2 1
18 novembre 2003
12
Come ritornare un valoreCome ritornare un valore
Il meccanismo del passaggio dei parametri ad un metodo essendo per valore è unidirezionale, il parametro viene inizializzato con l’argomento al momento della chiamata, se il parametro viene modificato l’argomento rimane immutato
Un metodo può restituire una sola variabile con la clausola returnreturn, il tipo di valore restituito deve essere indicato nella dichiarazione del metodo
18 novembre 2003
13
Uso di variabili globaliUso di variabili globali All’interno di una classe due metodi possono
scambiarsi dati utilizzando un campo della classe come variabile condivisa o globale
Questa forma di comunicazione non può essere usata fra metodi di classi diverse in quanto gli esemplari di classi diverse non accedono agli stessi campi
Ricordarsi infine che un metodo quando è invocato conosce i campi dell’esemplare della classe individuata dal riferimento usato per invocare il metodo detto talvolta parametro implicitoparametro implicito
Il valore del parametro implicito è accessibile con la clausola thisthis
18 novembre 2003
14
argomentoactual parameterparametro reale
parametroformal parameterparametro formale
all’attivazione o chiamata del metodoil valore dell’argomento viene utilizzato
per inizializzare il corrispondente parametro
return valore;
Alla terminazione del metodo il controllo viene passato alpunto di chiamata. I valore dei parametri vengono persi, inquanto si tratta di variabili locali allocate sul run-time stack(ma non vengono persi eventuali effetti collaterali).Il metodo può restituire un singolo valore
18 novembre 2003
15
Pacchetti (Pacchetti (packagepackage)) Una applicazione Java si compone di uno o più pacchetti Un pacchetto è un insieme di file (unità compilabili), un
pacchetto può essere organizzato gerarchicamente in sottopacchettisottopacchetti
In assenza di indicazioni contrarie i file contenuti nel directory di lavoro costituiscono un pacchetto senza pacchetto senza nomenome
Tutti gli esempi visti a lezione sono realizzati come pacchetti senza nome
Abbiamo visto in molti esempi come importare un componente di un pacchetto di libreria o l’intero pacchetto
18 novembre 2003
16
I nomi in JavaI nomi in Java Tutte le entità usate in un programma Java sono
individuate da nominomi, dette identificatoriidentificatori, composti da stringhe di caratteri alfanumerici con il primo carattere alfabetico
Ogni nome deve essere dichiaratodichiarato prima di essere usato, la dichiarazione specifica l’entità cui il nome si riferisce e chi può accedere al nome qualificandolo
Ogni nome semplicesemplice è riconosciuto in una porzione del programma detta il suo scopescope
Il significato di un nome è stabilito dal contestocontesto nel quale viene usato
18 novembre 2003
17
Le entità individuate da un nome possono essere– Una classe– Un’interfaccia– Un membro di una classe (campo o metodo)– Un parametro di un metodo, di un costruttore o
di un gestore di eccezione– Una variabile locale
Un nome semplicesemplice è costituito da un solo identificatore
Un nome qualificatoqualificato è costituito da più identificatori separati da un • (punto)
public class Coppia implements Comparablepublic class Coppia implements Comparable{ public Comparable chiave;{ public Comparable chiave; … …}}
public interface Stackpublic interface Stack{ void push (Object x);{ void push (Object x); … …}}
public class Coppia implements Comparablepublic class Coppia implements Comparable{ public Comparable chiave;{ public Comparable chiave; … … public String toString () { return chiave.toString() + ":" + attributo.toString(); }public String toString () { return chiave.toString() + ":" + attributo.toString(); }}}
public class Coppia implements Comparablepublic class Coppia implements Comparable{ …{ … public Coppia (Comparable c, Object a) { chiave = c; attributo = a; }public Coppia (Comparable c, Object a) { chiave = c; attributo = a; } public int compareTo (Object x) { return chiave.compareTo(((Coppia)x).chiave); }public int compareTo (Object x) { return chiave.compareTo(((Coppia)x).chiave); }}}
public static void main (String[] arg) throws IOExceptionpublic static void main (String[] arg) throws IOException { BufferedReader in = new BufferedReader(new FileReader(arg[0]));{ BufferedReader in = new BufferedReader(new FileReader(arg[0])); int n = 0;int n = 0; int somma = 0;int somma = 0; … …
while ((str = in.readLine()) != null)while ((str = in.readLine()) != null) { token = new StringTokenizer(str, ":");{ token = new StringTokenizer(str, ":"); int matricola = Integer.parseInt(token.nextToken());int matricola = Integer.parseInt(token.nextToken()); String nome = token.nextToken();String nome = token.nextToken(); dati[n++] = new Studente(nome, matricola);dati[n++] = new Studente(nome, matricola); }}
18 novembre 2003
18
Lo Lo scopescope Lo scope di una dichiarazione è la regione di un
programma nell’ambito della quale ci si può riferire ad una entità con il nome semplice
Lo scope del nome di una classe è l’intero pacchetto nel quale la classe compare
Lo scope di un membro di una classe è l’intera classe nella quale è dichiarato
Lo scope del nome di un parametro di un metodo o di un costruttore è l’intero corpo del metodo o del costruttore
Lo scope di una variabile locale dichiarata in un blocco si estende fino alla fine del blocco
Lo scope di una variabile locale dichiarata nell’inizializzazione di un ciclo for for si estende al solo corpo del ciclo
public class Coppia implements Comparablepublic class Coppia implements Comparable{ public Object attributo;{ public Object attributo; public Coppia (Comparable c, Object a) { chiave = c; attributo = a; }public Coppia (Comparable c, Object a) { chiave = c; attributo = a; } public int compareTo (Object x) { return chiave.compareTo(((Coppia)x).chiave); }public int compareTo (Object x) { return chiave.compareTo(((Coppia)x).chiave); } public String toString () { return chiave.toString() + ":" + attributo.toString(); }public String toString () { return chiave.toString() + ":" + attributo.toString(); } public Comparable chiave;public Comparable chiave;}}
int[] r = c.contiene();int[] r = c.contiene(); for (int i = 0; i < r.length; i++)for (int i = 0; i < r.length; i++) System.out.print(r[i] + ", ");System.out.print(r[i] + ", "); System.out.println();System.out.println(); c.togli(1);c.togli(1); r = c.contiene();r = c.contiene(); for (int i = 0; i < r.length; i++)for (int i = 0; i < r.length; i++) System.out.print(r[i] + ", ");System.out.print(r[i] + ", "); System.out.println();System.out.println(); for (int i = 0; i < 32; i++)for (int i = 0; i < 32; i++) if (c.appartiene(i))if (c.appartiene(i)) System.out.print("1");System.out.print("1"); elseelse System.out.print("0");System.out.print("0");
18 novembre 2003
19
Il controllo dell’accessoIl controllo dell’accesso
L’uso di nomi qualificatinomi qualificati consente di controllare l’accesso ai membri di una classe indipendentemente dallo scope, si danno 4 casi:– defaultdefault: accesso a livello di package– publicpublic: accesso da qualsiasi punto– privateprivate: accesso possibile solo dall’interno
della classe nella quale il nome è dichiarato– protectedprotected: accesso a livello di package e
nelle sottoclassi che estendono la classe
In genere i In genere i campicampi di una classe sono di una classe sono privateprivate (o (oprotected) in quanto si vuole che solo i metodiprotected) in quanto si vuole che solo i metodidella classe possano modificare il valore dei campidella classe possano modificare il valore dei campimentre i mentre i metodimetodi sono sono publicpublic perché devono poter perché devono poter essere utilizzati dall’esterno della classeessere utilizzati dall’esterno della classe
18 novembre 2003
20
Oscurare una dichiarazioneOscurare una dichiarazione
La dichiarazione di un nome all’interno di un blocco contenuto in un altro blocco può oscurare la dichiarazione più esterna
In genere è bene evitare di dichiarare la stessa variabile in blocchi diversi con significati diversi per evitare confusione (il compilatore non si il compilatore non si confonde!confonde! ma il lettore può rimanere confuso)
Vediamo ora un esempio di una dichiarazione che ne oscura un’altra in una situazione particolarmente insidiosa
18 novembre 2003
21
public class StackAr implements Stackpublic class StackAr implements Stack{ private Object[] v;{ private Object[] v; private int sp;private int sp; private static final int MAX = 10;private static final int MAX = 10; public StackAr ()public StackAr () { sp = 0;{ sp = 0; Object[] v = new Object[MAX];Object[] v = new Object[MAX]; }} public StackAr (int max)public StackAr (int max) { sp = 0;{ sp = 0; v = new Object[max];v = new Object[max]; }} public void push (Object x) { v[sp++] = x; }public void push (Object x) { v[sp++] = x; } public Object pop () throws Underflowpublic Object pop () throws Underflow { if (sp == 0){ if (sp == 0) throw new Underflow("Pop di stack vuoto");throw new Underflow("Pop di stack vuoto"); elseelse return v[--sp];return v[--sp]; }} public Object testa () throws Underflowpublic Object testa () throws Underflow { if (sp == 0){ if (sp == 0) throw new Underflow("Testa di stack vuoto");throw new Underflow("Testa di stack vuoto"); elseelse return v[sp-1];return v[sp-1]; }} public boolean vuoto () { return sp == 0; }public boolean vuoto () { return sp == 0; }}}
18 novembre 2003
22
I paradigmi di programmazioneI paradigmi di programmazione
Un programma deve essere comprensibile sia al compilatore (e alla macchina) sia all’uomo
È importante utilizzare paradigmi (modelli) di programmazione che aiutino a scrivere programmi corretti e facili da mantenere e modificare
Nel tempo si sono sviluppati molti paradigmi diversi nel tentativo di rendere più facile la produzione di programmi corretti e mantenibili
18 novembre 2003
23
La decomposizione funzionaleLa decomposizione funzionale
Per decomposizione funzionale si intende la tecnica con la quale si risolve un problema attraverso la composizione di sottoprogrammi o funzioni
Ad esempio dovendo leggere ed elaborare dei dati si scrive un sottoprogramma che legge i dati, uno che gli elabora ed un terzo che stampa i risultati
Il primo linguaggio che ha messo a disposizione strumenti per facilitare la decomposizione funzionale è stato il Fortran IV (fine anni ’50)
18 novembre 2003
24
La programmazione strutturataLa programmazione strutturata
Un programma si dice strutturato se è realizzato dalla composizione delle due sole strutture (o loro derivazione) if-then-elseif-then-else e while-dowhile-do
I linguaggi di programmazione moderni (sviluppati dopo l’invenzione del Pascal, inizio anni ‘70) sono per loro natura strutturati e quindi obbligano ad utilizzare naturalmente la programmazione strutturata
L’idea è così connaturata con i linguaggi moderni quali il C/C++ o Java che non è quasi più il casi di parlare di programmazione strutturata
18 novembre 2003
25
La modularizzazioneLa modularizzazione Per affrontare la costruzione di un grande progetto software
è necessario disporre di strumenti che consentano di costruire il software sotto forma di componenti indipendenti detti talvolta modulimoduli
Pascal (in origine) non consentiva nessuna forma di modularizzazione, un programma doveva essere sempre pensato come monolitico in quanto doveva contenere al suo interno tutte le procedure e funzioni necessarie
Il linguaggio C non dispone intrinsecamente di strumenti per la modularizzazione ma non la impedisce, è quindi possibile realizzare in C software modulare utilizzando le funzioni di macro elaborazionemacro elaborazione fornite dal linguaggio e strumenti esterni quali makemake per automatizzare le operazioni di espansione delle macro, compilazione e collegamento
18 novembre 2003
26
Modularizzazione (segue)Modularizzazione (segue)
I linguaggi Ada e Modula 2 sono stati progettati in modo da facilitare e rendere controllabile la modularizzazione. Hanno però avuto uno sviluppo limitato, il primo solo nell’ambiente delle commesse militari e spaziali, il secondo solo in un limitato ambiente accademico
Alcune estensione del linguaggio C quali C++ e in particolar modo il linguaggio orientato agli oggetti Eifell sono stati pensati in modo da facilitare la modularizzazione
18 novembre 2003
27
La programmazione orientata agli oggettiLa programmazione orientata agli oggetti
I linguaggio orientati agli oggetti mettono a disposizione una ricco repertorio di strumenti per la realizzazione di software in forma modulare
Package Incapsulamento (o information hiding)PolimorfismoEreditarietà
18 novembre 2003
28
Packages -> PacchettiPackages -> Pacchetti Un programma in Java è organizzato come un insieme di
pacchetti Ogni pacchetto ha un suo insieme di nomi per i tipitipi (classi
e interfacce) Un tipotipo dichiarato in un pacchetto è accessibile al di fuori
del pacchetto in cui è stato dichiarato solo se ha l’attributo publicpublic
I pacchetti sono organizzati in forma gerarchica come pacchetti e sottopacchetti
I pacchetti possono essere memorizzati come file o in un database
L’organizzazione in pacchetti facilita la modularizzazione isolando le scelte dei nomi di un pacchetto da quelle di ogni altro pacchetto
18 novembre 2003
29
IncapsulamentoIncapsulamentoPer incapsulamentoincapsulamento o information hidinginformation hiding si
intende la caratteristica di un linguaggio che consente di nascondere all’utente di un pacchetto (o anche in particolare di una sola classe) i dettagli con cui le funzionalità sono realizzate
Java consente di progettare pacchetti e classi in modo da nascondere in modo completo i dettagli realizzativi all’utente
18 novembre 2003
30
PolimorfismoPolimorfismo Il polimorfismopolimorfismo è la proprietà di un linguaggio orientato ad
oggetti per cui la decisione di quale metodo viene invocato tramite un riferimento viene stabilito al momento dell’esecuzione del programma in funzione del valore effettivamente assegnato al riferimento (in sintesi si parla di late bindinglate binding)
Java è intrinsecamente polimorfo Una forma elementare di polimorfismo è anche offerta dal
sovraccaricosovraccarico (overloadingoverloading) del nome di un metodo. Notare che il sovraccarico non richiede il late binding in quanto il compilatore può decidere quale metodo invocare dal confronto della forma della chiamata con la firma del metodo (nome e elenco del tipo degli argomenti)
18 novembre 2003
31
EreditarietàEreditarietà
L’ereditarietà consente di costruire una nuova classe che estende le funzionalità di un’altra classe senza avere accesso al codice sorgente della classe che si vuole estendere
Ereditarietà e polimorfismo sono funzionalità da utilizzare in modo coordinato
La programmazione orientata ad oggetti si caratterizza dalla possibilità di costruire l’estensione di una classe senza disporre del codice sorgente della classe da estendere combinata con la realizzazione del polimorfismo mediante late binding