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 typedef struct { int giorno; int mese; int anno; } Data; void stampadata(data d) { printf("%d", giorno); if (d.mese == 1) printf("gen"); else if (d.mese == 2) printf("feb"); printf("%d", anno); } La manipolazione dei dati avviene con accesso diretto alla rappresentazione del tipo: Data d; d.giorno=14; d.mese=12; } d.anno=2000; if (d.giorno == 27) paga_stipendi(); if (d.mese == 12) paga_tredicesime(); inizializzazione di un oggetto di tipo Data uso di un oggetto di tipo data 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 class Data { private int giorno; private int mese; private int anno;... giorno, mese, anno sono gli attributi di Data ATTRIBUTI Java 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 e valore degli attributi data1 Data giorno = 30 mese = 12 anno = 2001 nome della classe di cui l oggetto è istanza 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 Le operazioni definite nella classe sono chiamati i metodi della classe class Data {... public int leggi_giorno(){...}; public int leggi_mese(){...}; public int leggi_anno(){...};... } M E T O D I Java 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" analogia con le struct del C.. e la terminologia int a; -- a è una variabile di tipo int Data d; -- d è una variabile di classe Data Java 34
Oggetti mutabilii Lo stato degli oggetti (mutabili) può cambiare nel tempo, chiamando metodi opportuni data1 Data giorno = 30 mese = 12 anno = 2001 data1.giorno_dopo() data1 Data 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: 8 bit Dichiarazione di variabili short: 16 bit byte un_byte; int: 32 bit int a, b=3, c; long: 64 bit char c= h, car; float: 32 bit double: 64 bit Altri tipi: boolean: true false char: 16 bit, carattere Unicode boolean trovato=false; 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 xxx 3 giorno 11 mese 1991 anno Java 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 Creato con con la la prima primanew. Data Data Creato Creato con con la la seconda secondanew. new. Il Il riferimento riferimento al al primo primo oggetto oggetto Data Data èè perso. perso. Non Non c è c èpiù piùmodo di di accedere accedere all oggetto. all oggetto. L oggetto L oggetto verrà verràdistrutto dal dal garbage garbagecollector. Java 44
La visione a "run-time" i m k y h 6 "abcd" [0, 0, 0] 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); return d; } public static void main(string args[]) { Data x = foo();... /*d esiste solo sullo stack durante l esecuzione di foo(), ma viene deallocata quando foo() termina. Ma l oggetto costruito continua a vivere sullo heap!!!*/ d x xxx xxx 1 1 1990 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 Person[ ] person; person = new Person[20]; person[0] = new Person( ); E E definita definita solo solo la la variabile variabile person. person. L array L array vero vero e e proprio proprio non non esiste esiste person Java 51
Array di oggetti: Definizione B Person[ ] person; person = new Person[20]; person[0] = new Person( ); Ora Ora l array l array èè stato stato creato creato ma ma i i diversi diversi oggetti oggetti di di tipo tipo Person Personnon non esistono esistono ancora. ancora. person 0 1 2 3 4 16 17 18 19 Java 52
Array di oggetti: Definizione C Person[ ] person; person = new Person[20]; person[0] = new Person( ); Un Un oggetto oggetto di di tipo tipo persona persona èè stato stato creato creato e e un un riferimento riferimento a a tale tale oggetto oggetto èè stato stato inserito inserito in in posizione 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 Non viene allocato spazio per gli oggetti veri e propri f 0 1 2 3 4 5 6 7 8 9 Java 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; for (int n : a) result += n; return result; } n indica il generico elemento dell'arry, NON l'indice! 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; attributi Java 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); Al Quando momento la della funzione chiamata: termina, d1 e' 31/12/1999 d d1 xxx xxx 131 121 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); Al Quando momento la della funzione chiamata: termina, d2 e' 3/2/1984 d2 d xxx xxx 13 12 1990 1984 d1 yyy 3 2 1984 Java 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 Data giorno = 30 mese = 12 anno = 2001 data1.giorno_dopo() data1 Data 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 Stringin Java è un tipo riferimento (è definito da una classe) Due regole base: Variabile di tipo String è un oggetto, manipolato con un reference le stringhe sono immutabili (non si possono aggiungere o togliere caratteri a una stringa, ma occorre costruirne una nuova) (per avere stringhe mutabili si usa StringBuffer) Per le stringhe c è operatore di concatenamento + Costruttori: String() String(String s) Metodi (pubblici): int length() restituisce la lunghezza di 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() {...} int f(int x) {...} // corretto C ref = new C(); 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 }... significazero 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