1 Java Programming Language Introduzione al linguaggio di programmazione Java 29 giugno – 7 luglio 2007 Ing. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 2 Modulo 1 Modulo 1: Introduzione Questo modulo propone una panoramica generale del linguaggio di programmazione Java, delle sue principali peculiarità ed introduce le applicazioni in Java. Vengono illustrati i concetti di classi e di package nonché alcuni dei package Java usati più comunemente. Che cosa è il Java? Un linguaggio di programmazione Un ambiente di sviluppo Un Application Environment Un deployment Environment Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 3 Modulo 1 Obiettivi principali Il linguaggio di programmazione Java fornisce: Un linguaggio facile con cui programmare. • Elimina l’aritmetica dei puntatori e la gestione della memoria che hanno effetti sulla robustezza del codice. • E’ orientato agli oggetti per aiutare il programmatore a modellizzare i programmi in termini di “mondo reale”. • Fornisce una metodologia per produrre codice nella maniera più semplice e chiara possibile. Un ambiente interpretato che si traduce nei due seguenti benefici: • Velocità di sviluppo – Elimina la sequenza compile-link-load-test. • Portabilità del codice. Una modalità per i programmi di eseguire più di un thread contemporaneamente. Una modalità per modificare i programmi dinamicamente durante la loro esecuzione consentendo loro di caricare e scaricare moduli di codice. Una modalità per controllare i moduli caricati per assicurarne la sicurezza nella loro esecuzione. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 4 Modulo 1 Obiettivi principali L’architettura della tecnologia Java usa i seguenti tre concetti seguenti per raggiungere gli obiettivi elencati: La Java Virtual Machine (JVM) La Garbage Collection La sicurezza del codice Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 5 Modulo 1 La Java Virtual Machine La specifica della Java Virtual Machine definisce la virtual machine come: Una macchina immaginaria implementata emulandola via software in una macchina reale. Il codice per la Java Virtual Machine è memorizzato in uno o più file .class, ciascuno dei quali contiene il codice almeno per una public class. La specifica per la JVM fornisce le specifiche per le piattaforme hardware in cui tutto il codice Java è compilato. Queste specifiche abilitano il software Java ad essere “platform independent” poiché la compilazione è effettuata per una macchina generica nota come Java Virtual Machine (JVM). Questa “macchina generica” può essere emulata via software, per poter eseguire programmi nei vari sistemi già esistenti, oppure implementata via hardware. Il compilatore legge il codice sorgente della applicazione in Java e genera del bytecode. I Bytecode sono istruzioni in codice macchina per la JVM. Ogni interprete Java, non importa che sia un tool di sviluppo Java o un browser web che esegue delle applets, ha una propria implementazione della JVM. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 6 Modulo 1 Garbage Collection Molti linguaggi di programmazione consentono l’allocazione dinamica della memoria durante l’esecuzione dei programmi. Il processo di allocazione della memoria varia in funzione della sintassi del linguaggio, ma in tutti i casi produce un puntatore all’indirizzo iniziale di un blocco di memoria. Una volta che la memoria allocata non è più necessaria (il puntatore che referenzia la memoria è andato out of scope), il programma o l’ambiente di esecuzione (runtime environment) dovrebbe liberare la memoria. In C, C++ ed in altri linguaggi, lo sviluppatore del programma è responsabile della deallocazione della memoria. Questo potrebbe essere talvolta un compito oneroso, non essendo sempre noto in anticipo quando la memoria debba essere rilasciata. I programmi che non provvedono a deallocare la memoria non più necessaria inevitabilmente si bloccano quando non c’è più memoria disponibile da allocare. Il Java solleva il programmatore dalla responsabilità di deallocare la memoria. Esso fornisce un thread (sottoprocesso) al livello di sistema che tiene traccia di tutte le allocazioni della memoria. Durante i cicli di pausa della JVM, il thread della garbage collection effettua un controllo sulla memoria allocata e libera tutta quella non più necessaria. La Garbage Collection avviene automaticamente lungo tutta la durata della esecuzione di un programma in Java, eliminando la necessità di deallocare la memoria ed evitando “memory leaks” (perdite di memoria). D’altra parte, gli schemi della garbage collection possono variare in maniera consistente tra diverse implementazioni della JVM. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 7 Modulo 1 Sicurezza del codice Il Java Runtime Environment: Carica il codice – “class loader” Il class loader carica tutte le classi necessarie per l’esecuzione di un programma, ne aumenta la sicurezza separando i “namespaces” (spazio dei nomi) per le classi sul file system locale da quelle importate da sorgenti in rete. Questo limita ogni tipo di applicazione “Trojan horse” poiché le classi locali hanno sempre la precedenza ad essere caricate. Verifica il codice – “bytecode verifier” Il codice Java deve superare diversi test prima di poter essere eseguito sul proprio calcolatore. La JVM passa il codice attraverso un “bytecode verifier” che intercetta il formato dei frammenti di codice illegale che modificano i puntatori, violano i permessi di accesso agli oggetti o tentano di cambiare il tipo degli oggetti. Esegue il codice – “runtime interpreter” Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 8 Modulo 1 Una semplice applicazione Java 1. 2. 3. 4. 5. 6. 7. 8. // // Sample HelloWorld application // public class HelloWorldApp{ public static void main (Strings args []) System.out.println(“Hello World!”); } } { Queste linee sono lo stretto necessario per stampare sullo schermo la frase “Hello World!”. public – Il metodo main() può essere chiamato da chiunque, incluso l’interprete Java (dalla riga di comando). static – Indica al compilatore che il metodo main() è utilizzabile nel contesto della classe HelloWorldApp e dovrebbe essere eseguito prima di ogni altro metodo o istruzione. void – Indica the il metodo main() non ritorna niente. Questo è importante perché Java effettua un attento controllo dei tipi per confermare che il metodo chiamato ritorni un oggetto del tipo dichiarato dal metodo stesso. String args [ ] – E’ la dichiarazione di un array di String. Contiene gli argomenti presenti nella riga di comando seguiti dal nome della classe. Per esempio: java HelloWorldApp args[0] args[1] … … … System.out.println(“Hello World!”); Questa istruzione illustra l’uso del nome di una classe, del nome di un oggetto e della chiamata di un metodo. Stampa la stringa “Hello World!” sullo standard output usando il metodo println() dell’oggetto out di tipo PrintStream, referenziato dalla proprietà out della classe System. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 9 Modulo 1 Compilare ed eseguire HelloWorldApp Compilazione: Una volta creato il file sorgente HelloWorldApp.java, compilarlo con il seguente comando: C:\java\sources>javac HelloWorldApp.java Se il compilatore non restiruisce nessun messaggio, un nuovo file HelloWorldApp.class viene creato nella stessa directory del file sorgente, se non altrimenti specificato. Esecuzione: Per eseguire l’applicazione HelloWorldApp, usare l’interprete Java interpreter, java, posto nella directory bin. C:\java\sources>java HelloWorldApp Hello World! Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 10 Modulo 2 Modulo 2: Programmazione Orientata agli Oggetti Questo modulo dà una descrizione dei termini classe, oggetto, attributo, metodo e costruttore, spiega come scrivere il codice per definire un metodo, accedere alle variabili membro di un oggetto usando la “notazione punto” (dot notation), scrivere il codice per creare ed inizializzare un oggetto. Viene altresì spiegato l’uso della parola riservata “this” per accedere all’oggetto “corrente” ed è introdotto l’uso dei modificatori private e public. Si apprenderà l’uso delle asserzioni di package ed import per accedere alle librerie e l’uso della documentazione online delle Java Application Programming Interface (API). Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 11 Modulo 2 Che cosa è un oggetto (object)? Definizione: Un oggetto (object) è un insieme software di variabili e relativi metodi. Gli Object sono fondamentali per la comprensione della tecnologia object-oriented. Ci si può guardare intorno ed accorgersi di quanti oggetti esistono nel mondo reale che possiamo prendere come esempio: un cane, una scrivania, una tv, una bicicletta. Tutti questi oggetti nel mondo reale condividono due caratteristiche: Essi possiedono uno stato ed un comportamento. Per esempio, i cani hanno uno stato (nome, colore, razza, l’essere affamato) ed un comportamento (abbaiare, cercare, dimenare la coda). Una bicicletta ha uno stato (la marcia corrente, il ritmo della pedalata, due ruote, il numero delle marce) ed un comportamento (frenare, accelerare, rallentare, cambiare la marcia). Gli object software sono modellizzati in modo tale da riflettere in essi le caratteristiche che posseggono nel mondo reale in termini di stato e comportamento. • Un object mantiene il suo stato in una o più variabili. • Una variabile è un singolo dato riferito da un identificatore (nome della variabile). • Un object implementa i suoi comportamenti per mezzo dei metodi. • Un metodo è una funzione (subroutine) associata ad un object. Rappresentazione di un object: Metodi (comportamenti) Ignazio Testoni Variabili (stato) Rappresentazione di una bicicletta modellizzata in un object: Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 12 Modulo 2 Che cosa è una Classe (class)? Definizione: Una classe è il modello, o prototipo, che definisce le variabili e i metodi comuni a tutti gli oggetti di un certo tipo. Nel mondo reale certamente esistono diversi oggetti dello stesso tipo. Per esempio la nostra bicicletta è solo una delle tante che esistono nel mondo. Usando una terminologia object-oriented, si potrebbe dire che il nostro object bicicletta è una istanza della classe di oggetti noti come biciclette. Tutte le biciclette posseggono un certo stato (una marcia innestata, un certo ritmo di pedalata, due ruote) ed un certo comportamento (cambiare marcia, frenare) in comune. Ma certamente, lo stato di ciascuna bicicletta è indipendente e può essere diverso da quello di tutte le altre biciclette. Coloro che producono le biciclette si avvantaggiano del fatto che tutte le biciclette abbiano certe caratteristiche in comune, costruendo diverse biciclette per mezzo dello stesso modello. Sarebbe infatti estremamente inefficiente produrre un nuovo modello per ciascuna bicicletta da produrre. Nel software object-oriented è possibile allo stesso modo avere molti oggetti dello stesso tipo che condividano le stesse caratteristiche: rettangoli, schede per indirizzi, video clip, e così via. Proprio come per i produttori di biciclette, si può trarre vantaggio dal fatto che gli oggetti dello stesso tipo sono simili ed è possibile creare un modello per questi oggetti. Un modello software di un oggetto è chiamato classe. Rappresentazione della classe Bicicletta: Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 13 Modulo 2 Metodi speciali: i Costruttori Ogni oggetto può essere inizializzato in maniera diversa. Per esempio si può inizializzare un oggetto bicicletta di colore rosso e con 5 marce. Ma dovrebbe essere possibile inizializzare una bicicletta generica con un colore ed un numero di marce predefiniti. Si può inizializzare un oggetto chiamando un metodo speciale, il costruttore. Ogni oggetto può avere uno o più costruttori. I Costruttori sono definiti con le due regole seguenti: Il loro nome deve combaciare esattamente con il nome della classe. Essi non devono avere dichiarazione di tipo e non devo ritornare nulla al contrario dei normali metodi. public class Bicycle{ public Bicycle(){ // Costruttore senza argomenti (default constructor) // inizializza l’oggetto. } public Bicycle(int x, String color){ // Costruttore con argomenti // int, String – argomenti del costruttore // inizializza l’oggetto usando i parametri int x e String color. } } Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 14 Accedere ai metodi ed alle proprietà Modulo 2 Si può accedere ai metodi ed alle proprietà di un oggetto per mezzo della “dot notation”. package corso; // Bicycle.java import java.util.*; public class Bicycle{ int nGear; String color; public Bicycle(int g, String col){ this.setColor(col); } public void setColor(String col){ this.color=col; } public String getColor(){ return this.color; } } Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 15 Usare la documentazione online Java API Ignazio Testoni Ordine degli Ingegneri Provincia di Catania Modulo 2 29 giugno – 7 luglio 2007 16 Modulo 3 Modulo 3: identificatori, parole riservate, tipi Il linguaggio di programmazione Java contiene molti costrutti simili a quelli del linguaggio C. Questo modulo dà una panoramica generale dei costrutti disponibili e della sintassi generale richiesta da ciascun costrutto. Viene altresì introdotto un approccio di base object-oriented alla associazione di dati usando tipi di dati aggregati. Commenti: Si possono usare tre diversi stili di commenti: // commenti su una linea /* commenti su una o più linee */ /** commenti per la documentazione delle classi (JavaDoc) */ Punto e virgola, Blocchi, e Spazi: In Java, una asserzione è una singola linea di codice terminata da un punto e virgola(;). Per esempio: totale = a + b + c + d + e + f; Un blocco è un insieme di istruzioni racchiuso da parentesi graffe ({}). I blocchi di istruzioni sono anche usati per raggruppare le linee di codice appartenenti ad una classe. Gli spazi (whitespace) sono usati per separare i vari elementi del codice sorgente. E’ consentito un numero arbitrario di whitespace. Per whitespace si intendono gli spazi, tab, e ritorno a capo. E’ buona norma utilizzarli anche per rendere il codice sorgente più leggibile. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 17 Modulo 3 Identificatori In Java, un identificatore è un nome dato ad una variabile, una classe o un metodo. Gli identificatori iniziano con una lettera, underscore (_) o il simbolo del dollaro($). I caratteri successivi possono essere numeri. Gli identificatori sono case sensitive e non hanno una lunghezza massima. Quelli che seguono sono identificatori validi: identifier userName User_name _sys_var1 $change Un identificatore non può essere una parola riservata ma può contenerla come parte del suo nome. Per esempio, thisOne è un identificatore valido, ma this non lo è essendo this una parola riservata. Notazione Java per gli identificatori: Nomi delle classi: iniziano con lettera maiuscola, per esempio “MotorCycle”. Nomi delle variabili e dei metodi: iniziano con una lettera minuscola, per esempio: “gearsNumber” (variabile), “getGearsNumber()” (metodo). Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 18 Modulo 3 Tabella delle parole riservate abstract do implements private throw boolean double import protected throws break else instanceof public transient byte extends int return true case false interface short try catch final long static void char finally native super volatile class float new switch while continue for null synchronized default if package this Le parole in ROSSO sono i tipi di dato base in Java Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 19 Modulo 3 Tipi di dato Base in Java Il linguaggio Java definisce otto tipi di dato primitivi ed un tipo speciale. I tipi di dato primitivi si possono considerare in quattro categorie: Logico boolean Testuale char Intero byte, short, int, long Virgola mobile double, float I valori di tipo logico hanno solo due stati: true o false. Un valore di questo tipo è rappresentato dal tipo boolean. Esempio: // dichiarare la variabile truth come boolean // ed assegnarle il valore true boolean truth = true; Ignazio Testoni Caratteri singoli sono rappresentati usando il tipo char. Un char rappresenta un carattere unsigned Unicode a 16 bit. E’ necessario racchiudere un letterale char con le virgolette singole (‘’). • ‘a’ La lettera a. • ‘\t’ Un tab. • ‘\u????’ Uno specifico carattere Unicode dove ???? rappresentano 4 cifre esadecimali. Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 20 Modulo 3 byte, short, int, long La lunghezza in bit e l’intervallo dei valori per i quattro tipi di dato interi sono mostrati nella tabella seguente. La rappresentazione dell’intervallo dei valori è definita dalle specifiche Java come complemento a due ed è indipendente dal sistema (platform independent). Lunghezza Nome o Tipo Intervallo valori 8 bit byte da -27 a 27-1 16 bit short da -215 a 215-1 32 bit int da -231 a 231-1 64 bit long da -263 a 263-1 float e double Il formato di un numero in virgola mobile è definito usando le lunghezze mostrate in tabella ed è indipendente dal sistema usato. Ignazio Testoni Lunghezza Nome o Tipo 32 bit float 64 bit double Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 21 Modulo 3 Comprendere gli Oggetti I primi linguaggi di programmazione e tipicamente i programmatori alle prime armi tendono a trattare variabili individuali come entità isolate. Per esempio, se un programma deve manipolare una data, normalmente sarebbero necessari tre interi separati. int day, month, year; Questa istruzione fa due cose. Indica che, quando il programma si riferisce ad un giorno, mese o anno, sta trattando un tipo di dato intero. Essa alloca anche lo spazio necessario per questi interi. Benché questo approccio sia semplice da comprendere, ha due lacune significative. Per prima cosa, se il programma necessita di tracciare diverse date allora sono necessarie altre tre dichiarazioni per ciascuna data: int myBirthDay, myBirthMonth, myBirthYear; int yourBirthDay, yourBirthMonth, yourBirthYear; Questo metodo si rende velocemente noioso a causa del numero di variabili via via richieste. La sua seconda lacuna è che lo schema ignora l’associazione fra giorno, mese ed anno e tratta i tre valori in maniera indipendente. Ciascuna variabile è parte di una singola unità (in questo caso una data) e dovrebbe essere opportunamente considerata. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 22 Modulo 3 Creare un nuovo tipo Per superare queste due lacune il Java usa la classe (class) per creare nuovi tipi. Per esempio, per definire un tipo che rappresenti una data è necessario allocare spazio sufficiente per tre interi. Inoltre a questi tre interi deve essere attribuito il significato di giorno, mese ed anno: class MyDate{ int day; int month; int year; } La parola class è riservata e deve essere scritta in caratteri minuscoli. Il nome MyDate è scritto così per convenzione piuttosto che per necessità sintattiche. Si può dichiarare una variabile del tipo MyDate e le parti day, month, and year sono già implicite nella stessa dichiarazione: MyDate myBirth, yourBirth; Usando questa dichiarazione il Java rende disponibile l’accesso alle variabili (day, month, year), dette membri, usando l’operatore punto (.): myBirth.day = 26; myBirth.month = 11; yourBirth.year = 1960; Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 23 Modulo 3 Creare un oggetto Quando vengono dichiarate variabili di uno dei tipi primitivi (boolean, byte, short, int,…), lo spazio in memoria è allocato immediatamente in maniera automatica all’atto della dichiarazione stessa. La dichiarazione di una variabile, usando tipi non primitivi come String o Date, invece non alloca lo spazio necessario all’oggetto. Infatti, una variabile dichiarata di un tipo di classe non rappresenta il dato in se stesso ma rappresenta piuttosto un riferimento o puntatore ai dati. Ma prima di poter usare la variabile bisogna allocare la memoria necessaria. Per far questo si usa la parola riservata new nel modo che segue: MyDate myBirth; myBirth = new MyDate(); La prima istruzione, la dichiarazione, alloca solo lo spazio necessario per il puntatore. La seconda alloca lo spazio, chiamato oggetto, per i tre interi usati per formare MyDate. Gli assegnamenti relativi all’oggetto inizializzano la variabile myBirth affinché si riferisca correttamente al nuovo oggetto. Dopo che queste due operazioni sono state effettuate, il contenuto dell’oggetto MyDate è reso disponibile attraverso myBirth. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 24 Modulo 4 Modulo 4: Espressioni e controllo di flusso Questo modulo illustra le espressioni, incluso gli operatori e la sintassi del Java. Variabili e scope (ambito di validità). • Le variabili definite nell’ambito di un metodo sono dette variabili locali, talvolta riferite anche come automatiche, temporanee, o di stack. • Le variabili definite all’esterno di un metodo sono create allorché l’oggetto è costruito usando la chiamata new Xyz(). Esistono due tipi possibili di variabili. Il primo tipo è la variabile di classe che è dichiarata usando la parola riservata static. Essa viene creata nel momento in cui la classe è caricata. Le variabili di classe persistono in memoria fino a che la classe non viene scaricata. Il secondo tipo è una variabile di istanza (instance variable), dichiarata senza la parola riservata static. Le variabili di istanza continuano ad esistere finché l’oggetto risulta referenziato. Talvolta questo tipo di variabili sono dette variabili membro in quanto sono membri di una classe. La parola riservata static sarà discussa in seguito più dettagliatamente. • Le variabili parametro in un metodo definiscono gli argomenti passati in una chiamata ad un metodo. Ogni qualvolta un metodo viene invocato, una nuova variabile viene creata e termina solo quando il metodo ha terminato la sua esecuzione. Esempio: OurClass.java Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 25 Modulo 4 Inizializzazione delle variabili Nessuna variabile in Java si può usare se prima non viene inizializzata. Quando un oggetto viene creato, le variabili di istanza vengono inizializzate con i seguenti valori nel momento in cui la memoria viene allocata. byte 0 short 0 int 0 long 0L float 0.0F double 0.0D char ‘\u0000’ (NULL) boolean false All reference type null Nota – I caratteri L, F, D sono facoltativi e servono sono a ricordare il tipo di variabile. Nota – Un puntatore che ha valore null non si riferisce a nessun oggetto. Ogni tentativo di usare l’oggetto causa una eccezione (exception). Le eccezioni sono errori che accadono a runtime e verranno discusse in seguito. Mentre le variabili definite all’esterno di un metodo sono inizializzate automaticamente, le variabili locali devono essere inizializzate manualmente prima del loro uso. Il compilatore riporta un errore se determina una condizione dove una variabile potrebbe essere usata prima di essere inizializzata. (Inizializzazione.java) Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 26 Modulo 4 Espressioni - Operatori Gli operatori in Java sono simili, per stile e funzione, a quelli del C o C++. La seguente tabella elenca gli operatori in ordine di precedenza (da L a R significa da sinistra a destra) Separatore . [] () ; , da R a L ++ -- + - ~ ! (data type) da L a R * / % da L a R + - da L a R << >> >>> da L a R < > <= >= instanceof da L a R == != da L a R & da L a R ^ da L a R | da L a R && da L a R || da R a L ?: da R a L = *= /= %= += -+ <<= >>= >>>= &= ^= |= Ignazio Testoni Gli operatori && (AND) e || (OR) valutano espressioni logiche di tipo short-circuit: MyDate d = null; if ((d != null) && (d.day > 32)){ // do something with d } L’espressione di tipo boolean che forma l’argomento dell’istruzione if() è lecita e completamente sicura. Lo è perché la seconda sub-espressione viene ignorata quando la prima sub-espressione è falsa, essendo l’intera espressione sempre falsa quando è falsa la prima, non importa quale sia il valore della seconda. Nota - instanceof è una parola riservata solo in Java. Gli altri operatori possono essere comuni anche in altri linguaggi. Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 27 Modulo 4 Espressioni - Operatori Concatenazione di stringhe (String) con + L’operatore + effettua la concatenazione di oggetti di tipo String, producendo un nuovo oggetto String. String salutation = “Dr. ”; String name = “Pete ” + “Seymour.”; String title = salutation + name; Il risultato dell’ultima riga è: Dr. Pete Seymour. Se uno dei due argomenti dell’operatore + è un oggetto String, allora l’altro viene automaticamente convertito in String. Ogni object può essere convertito automaticamente in String, benché il risultato a volte può risultare apparentemente senza senso. Un oggetto che non è di tipo String viene convertito in una stringa equivalente per mezzo del metodo toString(). Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 28 Modulo 4 Espressioni - Casting Il casting consiste nell’assegnazione di un tipo ad una variabile di un altro tipo. Se i due tipi sono compatibili, il Java effettua la conversione automaticamente. Per esempio, un valore di tipo int può sempre essere assegnato ad una variabile di tipo long. Qualora il casting comporti perdita di informazione, il compilatore richiede che si confermi l’assegnazione con un ‘typecast’. Questo per esempio si può fare forzando un valore di tipo long in una variabile di tipo int. Il casting esplicito ha la sintassi seguente: long bigValue = 99; int squashed = (int)(bigValue); Il tipo di variabile in cui si vuole fare il casting è posto fra parentesi ed usato come prefisso all’espressione da modificare. Benché non sempre necessario, è consigliabile racchiudere l’intera espressione tra parentesi. In questo modo il codice risulta più leggibile mentre viceversa, la precedenza fra le operazioni di casting potrebbe creare problemi. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 29 Promozione e Casting di Espressioni Modulo 4 Le variabili possono essere promosse ad una forma più lunga (in termini di bit), se non vi è perdita di informazione. long bigValue = 6; // 6 è un tipo int, OK int smallValue = 99L; // 99L è un long, illegale double z = 12.414F; // 12.414 è un float, OK float z1 = 12.414; // 12.414 è un double, illegale In generale si può dire che una espressione è compatibile in assegnamento se il tipo di variabile è lunga (in termini di bit) almeno quanto il tipo dell’espressione. Per l’operatore +, quando i due operandi sono tipi numerici primitivi, il risultato è almeno un int ed ha un valore calcolato promuovendo il risultato al tipo più grande fra i due operandi. Questo potrebbe però causare un overflow o una perdita di precisione. Per esempio il frammento di codice seguente short a, b, c; a = 1; b = 2; c = a + b; causa un errore perché esso promuove ciascun short ad un int prima di operare su di loro. Invece se c fosse dichiarato come int o se venisse fatto un typecast del tipo: c = (short)(a+b); Il codice funzionerebbe. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 30 Costrutti condizionali - if Modulo 4 Istruzioni if, else La sintassi fondamentale per le istruzioni if, else è: if ( boolean expression ){ istruzione o blocco di istruzioni; }else{ istruzione o blocco di istruzioni; } Opzionalmente si possono aggiungere più condizioni alternative: if ( boolean expression1 ){ istruzione o blocco di istruzioni; }else if ( boolean expression2 ){ istruzione o blocco di istruzioni; }else if ( boolean expression3 ){ istruzione o blocco di istruzioni; }else{ istruzione o blocco di istruzioni; } Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 31 Modulo 4 Costrutti condizionali - switch Istruzione switch Esempio 1: La sintassi per l’istruzione switch è: switch (expression1 ){ case constant2: statements; break; case constant3: statements; break; default: statements; break; } L’etichetta opzionale default è usata solo per specificare il segmento di codice da eseguire quando il valore della variabile o l’espressione valutata da switch non corrisponde a nessuno dei valori specificati nei vari valori case. Se non c’è l’istruzione break come ultima istruzione del segmento di codice relativo a ciascun case l’esecuzione continua nel segmento di codice del case successivo senza verificare il valore del relativo case. Ignazio Testoni int colorNum = 0; switch (colorNum ){ case 0: setBackground(Color.red); break; case 1: setBackground(Color.green); break; default: setBackground(Color.black); break; } Esempio 2: switch (colorNum ){ case 0: setBackground(Color.red); case 1: setBackground(Color.green); default: setBackground(Color.black); break; } Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 32 Modulo 4 Costrutti ciclo (loop) - for() I costrutti del tipo ciclo consentono di ripetere l’esecuzione di un certo blocco di istruzioni. Il Java supporta tre tipi di questi costrutti: i cicli for, while e do. Ciclo for La sintassi per il ciclo for è: for(init_expr [, init_expr2, init_expr3…] ; boolean test_expr; alter_expr){ istruzione o blocco di istruzioni; } Esempio: for ( int i = 0; i < 10; i++ ){ System.out.println(“Are you finished yet ?”); } System.out.println(“Finally !”); Nota – E’ consentito usare la virgola all’interno del ciclo for(). Per esempio, for ( i = 0, j = 0; j < 10; i++, j++) {} è lecito. Nel precedente esempio, int i è dichiarato e definito contestualmente all’interno del blocco for. La variabile i è accessibile solo all’interno del blocco di questo ciclo for; Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 33 Modulo 4 Costrutti ciclo (loop) - while() Ciclo while La sintassi del ciclo while è: while (bolean test_expr) { istruzione o blocco di istruzioni; } Esempio: int i = 0; while ( i < 10 ){ System.out.println(“Are you finished yet ?”); i++; } System.out.println(“Done !”); Accertarsi sempre che la variabile di controllo sia opportunamente inizializzata prima che il blocco del ciclo inizi la sua esecuzione ed accertarsi che la condizione sia true perché esso possa iniziare. E’ necessario sempre aggiornare la variabile in maniera adeguata per prevenire la condizione di ciclo infinito. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 34 Modulo 4 Costrutti ciclo (loop) - do() Ciclo do La sintassi del ciclo do è: do { istruzione o blocco di istruzioni; } while (boolean test); Esempio: int i = 0; do { System.out.println(“Are you finished yet ?”); i++; }while ( i < 0); System.out.println(“Done !”); Proprio come i cicli while, acertarsi che la variabile di controllo del ciclo sia opportunamente inizializzata, aggiornata all’interno del ciclo ed appropriatamente controllata. • Usare il ciclo for nei casi in cui il ciclo debba essere eseguito un numero predeterminato di volte. • Usare i cicli while e do nei casi in cui non è possibile predeterminare il numero dei cicli da eseguire. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 35 Modulo 5 Modulo 5: Array In questo modulo si descrive come sono dichiarati, creati, inizializzati e copiati gli array in Java Dichiarazione di un array: Gli array sono usati tipicamente per raggruppare oggetti dello stesso tipo. Gli array consentono di riferirsi al gruppo di oggetti per mezzo di un unico nome. Si possono dichiarare array di qualsiasi tipo, sia primitivo, sia di classe: char s[]; Point p[]; // dove Point è una classe. In Java, un array è un aggetto anche se l’array è composto da tipi primitivi e, come gli altri tipi di classe, la dichiarazione non crea automaticamente l’oggetto stesso. Piuttosto, la dichiarazione di un array crea un puntatore (reference) che si deve usare per indirizzare l’array. La memoria necessaria usata dagli elementi dell’array è allocata dinamicamente o tramite l’istruzione new o tramite un inizializzatore di array. Il Java permette una forma alternativa con le parentesi quadre a sinistra: char [] s; Point [] p; // dove Point è una classe. Entrambi i formati sono usati e la dichiarazione non specifica la dimensione dell’array. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 36 Modulo 5 Creazione di un array Gli array si possono creare come tutti gli altri oggetti, usando l’istruzione new: s = new char[20]; p = new Point[100]; Il primo crea un array di 20 elementi di tipo char (primitivo). Il secondo crea un array di 100 elementi di tipo Point (oggetto). Ma non crea 100 oggetti di tipo Point. Questi debbono essere creati separatamente: p[0] = new Point(); p[1] = new Point(); ... oppure for(int c = 0; c < 100; c++){ p[c] = new Point(); } L’indice usato per indirizzare i singoli elementi di un array inizia sempre da zero e deve rimanere sempre in un intervallo compreso fra zero ed un valore comunque minore della lunghezza dell’array. Qualsiasi tentativo di accedere ad un elemento dell’array non compreso in questo intervallo (0 -> N-1) crea un errore a runtime. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 37 Modulo 5 Inizializzazione di un array Quando si crea un array, ciascun elemento viene inizializzato. Nel caso dell’array di char s, nella sezione precedente, ciascun valore è inizializzato a zero ('\u0000' – carattere null). Nel caso dell’array p ciascun valore è inizializzato a null, indicando cioè che ancora non ci si riferisce ad un oggetto di tipo Point. Dopo che l’assegnazione p[0] = new Point() è stata fatta, il primo elemento dell’array si riferisce ad un oggetto Point reale, allocandone così la relativa memoria. Nota – Inizializzare tutte le variabili, incluso gli elementi degli array, è essenziale per la sicurezza del sistema. Non si deve mai fare uso di variabili senza prima inizializzarle. Il Java consente una forma abbreviata per creare array e nello stesso tempo inizializzarne i valori: String names [] = { "Paul", "George", "Linda" }; Bycicle [] cycles = { new Bycicle(Color.red), new Bycicle(Color.black), new Bycicle(Color.grey) }; Ignazio Testoni Inizializzatore di array Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 38 Modulo 5 Array multidimensionali In Java gli array multidimensionali si usano diversamente dagli altri linguaggi. Poiché è consentita la creazione di array di qualunque tipo, essendo un array a sua volta un oggetto, si possono creare array di array (e array di array di array) e così via. L’esempio seguente mostra un array bidimensionale: int twoDim [] [] = new int [4] []; twoDim[0] = new int[5]; twoDim[1] = new int[5]; L’oggetto creato dalla prima chiamata new è un array che contiene quattro elementi. Ciascun elemento deve essere inizializzato separatamente cosicché ciascun elemento punti al suo array. Poiché gli elementi si inizializzano separatamente, è possibile creare array di array non rettangolari. Cioè, gli elementi di twoDim si possono così inizializzare: twoDim[0] twoDim[1] twoDim[2] twoDim[3] = = = = new new new new int int int int [2]; [4]; [6]; [8]; Questo tipo di inizializzazione risulta piuttosto noiosa, e poiché la forma più comune di array bidimensionale è di tipo rettangolare, esiste una forma abbreviata per creare array bidimensionali. L’esempio mostra la creazione di un array di quattro array di cinque interi ciascuno. int twoDim [] [] = new int [4] [5]; Il numero degli elementi in un array è memorizzato come parte dell’oggetto array stesso nella proprietà o attributo length. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 39 Modulo 6: Struttura delle classi Modulo 6 Questo modulo porta l’introduzione ai concetti degli oggetti in Java descritti nel modulo 2 ad un livello successivo, considerando i concetti di overloading, overriding, subclassing, ed un approfondimento sui costruttori. La programmazione orientata agli oggetti (OOP) consente di modellizzare concetti del mondo reale all’interno di un programma per computer. In essa si possono trovare le caratteristiche della programmazione strutturata ed un meccanismo per organizzare dati ed algoritmi. I concetti fondamentali dei linguaggi OOP sono tre: Incapsulamento, polimorfismo, ed ereditarietà. Tutti e tre sono indissolubilmente legati al concetto di classe. Definizione dei metodi: Il Java utilizza un approccio simile ad altri linguaggi, particolarmente C and C++, per definire i metodi. Le dichiarazioni hanno la forma seguente: < modificatore > < tipo di oggetto > < nome > ( [< lista argomenti >] ) [throws < exception >] { ... } • < nome >: può essere qualunque identificatore lecito. • < tipo di oggetto >: tipo di valore restituito dal metodo. • < modificatore >: public, private, protected, static... • < lista argomenti >: argomenti passati al metodo. • throws < exception >: riporta un eventuale specifico errore all’atto della chiamata del metodo. Per Esempio, public void addDays( int days ){ < block > // Blocco di istruzioni … } Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 40 Modulo 6 Passaggio per valore Il Java passa gli argomenti esclusivamente “per valore”; cioè, l’argomento non può essere cambiato dalla chiamata al metodo. Quando l’istanza di un oggetto è passata come argomento ad un metodo, il valore dell’argomento è il riferimento all’oggetto. Il contenuto dell’oggetto può essere cambiato nel metodo chiamato, ma il riferimento all’oggetto invece non può mai essere cambiato. Car ferrari = new Car(); ferrari.setSpeed(65); changeParameters(ferrari); System.out.println(“The speed = “+ferrari.getSpeed()); public void changeParameters(Car c){ //changes the car’s speed outside this method! c.setSpeed(200.0); } Il risultato stampato dipende da cosa succede all’interno del metodo changeParameters(): “The speed = 200” PerValore.java Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 41 Modulo 6 Incapsulamento Con l’uso della parola riservata private, nella dichiarazione di day, month, year nell’oggetto MyDate, si rende impossibile l’accesso a queste varabili membro da parte di qualunque blocco di codice a meno che il codice che tenti di accedere ai membri private appartenga alla classe stessa. Prevenire l’accesso diretto alle variabili potrebbe sembrare strano, ma consente enormi vantaggi per la qualità del programma che usa la classe MyDate. Poiché i singoli elementi di dato sono inaccessibili, l’unico modo che c’è per leggerli o modificarli è attraverso i metodi. Se un programma richiede la consistenza interna dei membri della classe è possibile ottenerla per mezzo dei metodi della classe stessa. MyDate d = new MyDate(2003, 2, 28); d.day = 31; // giorno inesistente !!! d.month = 19; // mese inesistente !!! Si può verificare la consistenza del dato mese con un metodo appropriato: public void setMonth(int m){ if (m < 13 && m > 0){ this.month = m; }else{ System.out.println(“Il mese ”+m+” non è un numero di mese valido !”); } } Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 42 Overload dei nomi dei metodi Modulo 6 In certe circostanze potrebbe risultare comodo scrivere diversi metodi nella stessa classe che fondamentalmente facciano la stessa cosa ma con argomenti diversi. Per esempio il metodo println(): public public public public void void void void println(int i) println(float f) println(String s) println() La lista degli argomenti deve essere diversa. Il tipo restituito potrebbe essere diverso. Java permette di riutilizzare un nome per più di un metodo. I nomi dei metodi si possono riutilizzare a condizione che le signature (numero e tipo degli argomenti) dei metodi siano tutte diverse. Se così non fosse si verrebbero a creare delle ambiguità che ovviamente non sono ammesse. Nel caso dei tre metodi println le signature sono diverse essendo sempre diversi gli argomenti con cui sono dichiarate. Il Java allora sceglie il metodo da eseguire in base al tipo di argomenti con cui viene chiamato il metodo. La lista degli argomenti nella dichiarazione di un metodo è detta appunto method signature. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 I costruttori 43 Modulo 6 L’istruzione: MyDate birthDate = new MyDate(); dichiara ed effettua l’inizializzazione del nuovo oggetto birthDate, istanza della class MyDate. La fase finale dell’inizializzazione di un nuovo oggetto è quella di eseguire un metodo chiamato costruttore. I costruttori sono identificati da due regole: • Il nome del metodo deve essere esattamente identico al nome della classe. • Esso non deve ritornare nessun tipo di dato nella dichiarazione. Esattamente come un normale metodo, è possibile effettuare l’overload del costruttore con altri costruttori ovviamente con diverse signature. Quando si esegue una chiamata new Xyz(lista_argomenti), la signature determina quale costruttore debba essere usato. public class Bicycle{ private int gears=5; private String color="black"; private String name="no name"; public Bicycle(){ // costruttore predefinito } public Bicycle(int gears, String color){ // int, String // costruttore this.gears = gears; this.color=color; } public Bicycle(int gears, String color, String name){ this(gears, color); this.name = name; } } Ignazio Testoni Ordine degli Ingegneri Provincia di Catania – args 29 giugno – 7 luglio 2007 44 Ereditarietà (subclassing) Modulo 6 I linguaggi OOP possiedono uno speciale meccanismo che consente al programmatore di definire una classe partendo da una classe già definita in precedenza. A tale scopo si usa la parola riservata extends: public class Employee { String name; String hireDate; Date dateOfBirth; String jobTitle; int grade; ... } public class Manager extends Employee { String department; Employee subordinates []; ... } Ignazio Testoni In questo caso la classe Manager è definita in modo tale da avere tutti i metodi e tutte le proprietà che ha la classe Employee. Tutti i metodi e tutte le proprietà sono ereditate dalla definizione della classe genitore. Tutto quello che il programmatore deve fare è di definire le caratteristiche in più o specificare quali cambiamenti apportare (alla classe Employee). Questo approccio rappresenta un grande miglioramento in termini di manutenibilità ed affidabilità del codice. Se viene apportata una correzione alla classe Employee, allora anche la classe Manager sarà corretta automaticamente senza che il programmatore debba fare nulla ad eccezione di una ricompilazione. E’ consentito estendere solo una classe. Il Java infatti supporta solo la singola ereditarietà. Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 45 Modulo 6 Ereditarietà singola Employee attributi name address salary Engineer Due modi per includere un costruttore sono: • Usare il costruttore di default • Scrivere uno o più costruttori espliciti Secretary Manager extends Employee metodi upSalary attributi bonus metodi upBonus Director extends Manager attributi car allowance metodi upAllowance • Una sottoclasse eredita tutti i metodi e le variabili dalla superclasse • La sottoclasse non eredita il costruttore Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 46 Modulo 6 Polimorfismo Il polimorfismo è la capacità per un oggetto di avere forme differenti; per esempio la classe Manager ha accesso ai metodi della classe Employee. • Un oggetto ha solo una forma. • Una variabile reference ha diverse forme; essa può riferirsi ad oggetti di forma diversa. Una variabile è polimorfica in quanto può riferirsi ad oggetti dalle forme diverse. In Java c’è solo una classe genitore di tutte le classi, la classe java.lang.Object. La classe Object definisce una serie di metodi utili, incluso toString(), motivo per cui ogni oggetto in Java può essere convertito in una rappresentazione di tipo String. Java consente di riferirsi ad un oggetto tramite una variabile del tipo della classe genitore. Così è possibile dire: Employee e = new Manager(); Riferendosi però alla variabile e così com’è, si può accedere solo a quelle parti dell’oggetto che sono parte di Employee; le parti specifiche relative a Manager non sono disponibili. Employee Ignazio Testoni Manager Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 47 Modulo 6 Polimorfismo: un esempio Si definisca una generica classe FiguraGeometrica che abbia i seguenti metodi: getArea() getPerimeter() getName() // calcola il area // calcola il perimetro // leggi il nome Si definiscano le seguenti classi che estendano FiguraGeometrica e che abbiano le loro proprie implementazioni dei metodi suddetti: Cerchio Triangolo PoligonoRegolare extends FiguraGeometrica extends FiguraGeometrica extends FiguraGeometrica Si definisca la classe Calcola che dichiari un array di oggetti FiguraGeometrica. L’array in questione deve contenere varie istanze di oggetti del tipo delle classi sopraelencate e ne deve calcolare area e perimetro. FiguraGeometrica.java Cerchio.java Triangolo.java Calcola.java Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 48 Modulo 6 L’operatore instanceof public class Employee extends Object public class Manager extends Employee public class Contractor extends Employee Dato il fatto che è possibile referenziare un oggetto tramite una delle sue classi genitore, talvolta si ha la necessità di sapere effettivamente a quale classe appartenga un determinato oggetto. Per questo scopo si usa l’operatore instanceof. Nota – Ricordarsi che, benché accettabile, extends Object è sempre ridondante. public void method (Employee e) { if (e instanceof Manager) { // Richiedi benefit, stock options // nonché il salario opportuno } else if (e instanceof Contractor ) { // Richiedi la tariffa oraria } else { // impiegato normale… } } Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 49 Modulo 6 Casting di oggetti Se non si fa uso dell’operatore instanceof, si corre il rischio di fallire il casting. Generalmente ogni tentativo di effettuare un cast ad un reference di un oggetto è soggetto a diversi controlli: Effettuare un “up casting” attraverso la gerarchia delle classi è sempre consentito. Infatti si fa tramite un normale assegnamento. Per effettuare il “down casting”, il compilatore deve verificare che il casting sia possibile. Per esempio, ogni tentativo di effettuare un cast da Manager a Contractor è assolutamente non consentito, poiché Contractor non è certamente un Manager. La classe verso cui si voule fare il casting deve essere una sottoclasse del reference dell’oggetto che deve effettuare il casting. Se al livello di compilazione il casting è consentito, allora l’oggetto sarà verificato a runtime. Per esempio, succede che se il controllo di instanceof è omesso dai sorgenti, e l’oggetto da promuovere di fatto non è un oggetto del tipo voluto, durante il runtime verrà generata una eccezione. Employee Contractor Ignazio Testoni Manager Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 50 Overriding dei metodi (sovrascrittura) Modulo 6 Se in una classe figlio viene definito un metodo che ha lo stesso nome, lo stesso return type e la stessa signature di un metodo della classe padre, si dice allora che il nuovo metodo effettua l’override di quello vecchio. Una sottoclasse può modificare i comportamenti ereditati dalla classe genitore. Una sottoclasse può creare un metodo con funzionalità diverse rispetto a quelle della classe genitore ma con gli stessi: • Nome • Return type • Lista degli argomenti public class Employee { String name; int salary; public String getDetails(){ return “Name: ” + name + “\n” +“Salary: ” + salary; } } Ignazio Testoni public class Manager extends Employee { String department; public String getDetails(){ return “Name: ” + name + “\n” + “Manager of ” + department; } } // Il metodo originario getDetails è stato sovrascritto Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 51 Modulo 6 L’istruzione super L’istruzione super si riferisce alle superclasse della classe in cui l’istruzione è usata. Essa si usa per fare riferimento alle variabili membro o ai metodi della superclasse. Invocare i costruttori della classe genitore: Talvolta si definisce un costruttore che prende degli argomenti e si vuole usare questi argomenti per controllare la costruzione della parte padre di un oggetto. Si può invocare uno specifico costruttore della classe padre come parte della inizializzazione della classe figlio invocando l’istruzione super dalla prima linea del costruttore figlio. public class Employee { String name; public Employee (String n){ this.name = n; } } public class Manager extends Employee { String department; public Manager (String n, String d){ super(n); this.department = d; } } Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 52 Modulo 6 Raggruppare le classi Packages: Il Java prevede il meccanismo dei package per raggruppare classi correlate fra loro. E’ possibile indicare che le classi di un file sorgente appartengono ad un particolare package usando l’istruzione package: La dichiarazione del package se esiste, deve trovarsi all’inizio del file sorgente. E’ consentito dichiarare solo un package all’interno di un sorgente e questa dichiarazione ha validità in tutte le parti del file sorgente. I nomi dei package sono gerarchici e sono separati da un punto. I package sono salvati in una directory ad albero che contiene un ramo che è appunto il nome del package. Il file Employee.class dovrebbe essere presente all’nterno della directory: path/abc/financeDept/ L’opzione –d specifica al compilatore la radice della gerarchia del package in cui i file .class sono salvati. Ignazio Testoni // Class Employee of the Finance department // for the ABC company. package abc.financeDept; public class Employee { ... } Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 53 Modulo 6 Raggruppare le classi L’istruzione import: Indica al compilatore dove cercare le classi da usare Precede tutte le dichiarazioni della classe // La classe Manager appartiene al package attuale. // La classe Manager appartiene al package attuale. import abc.financeDept.*; public class Manager extends Employee { String department; Employee subordinates []; ... } public class Manager extends abc.financeDept.Employee { String department; Employee subordinates []; ... } Il nome del package fa parte del nome completo di una classe. Ci si può riferire alla classe Employee con abc.financeDept.Employee, oppure si può usare l’istruzione import e solamente il nome della classe Employee. Quando si usa una dichiarazione package, non è necessario importare lo stesso package o tutti gli elementi del package. Il package attuale, che sia implicito od esplicito, fa sempre parte dello spazio dei nomi attuale. L’istruzione import specifica solo la classe cui si vuole accedere. Per avere accesso a tutte le classi di uno stesso package, usare il simbolo “*”: import java.awt.*; Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 54 Modulo 7: caratteristiche avanzate delle classi Modulo 7 Variabili di classe (static) Sono condivise fra tutte le istanze della classe. Possono essere etichettate sia public che private. Se etichettate public possono essere lette dal di fuori della classe anche se la classe non è stata istanziata. In questo esempio, ad ogni oggetto creato viene assegnato un unico numero seriale, partendo da 1. La variabile contatore è condivisa fra tutte le istanze, in modo che quando il costruttore di un oggetto incrementa il contatore, l’oggetto successivamente creato riceve il valore incrementato. Una variabile di tipo static è assimilabile alle variabili globali per altri linguaggi. Se un variabile static è di tipo public, è possibile accedervi dall’esterno della classe. Per poterlo fare non è necessario avere un’istanza della classe ma vi si può accedere indirizzandola per mezzo del nome della classe in cui è definita. Ignazio Testoni public class Count { private int serialNumber; private static int counter = 0; public Count(){ counter ++; serialNumber = counter; } } public class StaticVar { public static int number; } public class OtherClass { public OtherClass(){ int x = StaticVar.number; } } Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 55 Modulo 7 Caratteristiche avanzate delle classi - static Metodi statici (static) E’ possibile invocare un metodo di tipo static senza la necessità di dover istanziare la classe a cui il metodo appartiene. Si può accedere ad un metodo static usando il nome della classe piuttosto che una sua istanza Poiché si può invocare un metodo statico senza alcuna istanza della classe a cui appartiene, un metodo statico non può accedere a nessuna variabile che non sia definita all’interno del metodo stesso o che non sia statica a sua volta. Ogni tentativo di riferimento a variabili non static causa un errore di compilazione. public class Wrong { int x; public static void main(String [] args){ x = 9; // ERRORE IN COMPILAZIONE !!! } } Circa i metodi statici: • main() è static poiché deve essere eseguito prima che sia eseguita ogni altra istanza. • Quando main() inizia, nessun oggetto è ancora stato creato. • Un metodo static non può essere sovrascritto (overriden) da un metodo non static. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 56 Caratteristiche avanzate delle classi - final Modulo 7 Parola riservata final Classi final Se una classe è etichettata come final essa non può essere estesa. Per esempio, la classe java.lang.String è una classe final. Questo per ragioni di sicurezza, poiché essa assicura che se un metodo ha dei riferimenti ad un oggetto di tipo String, questo sia certamente una istanza della classe String senza che alcuno ne abbia potuto modificare le proprietà o i metodi. Metodi final I metodi dichiarati come final non possono essere sovrascritti (overridden). Anche questo per motivi di sicurezza. Un metodo dovrebbe essere reso final se esso ha una implementazione che non deve essere cambiata e che è critica per la consistenza dell’oggetto in sé. Tutti i metodi dichiarati static o private sono automaticamente final. Variabili final Dichiarare una variabile final ha l’effetto di renderla costante. Ogni tentativo di modificare il contenuto di una variabile final genera un errore in compilazione. public final int MAX_ARRAY_SIZE = 25; NOTA – Una variabile di tipo reference (istanza di classe) dichiarata come final non può riferirsi ad alcun altro oggetto. E’ invece possibile modificarne lo stato essendo final solo il suo reference. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 57 Caratteristiche avanzate delle classi - abstract Modulo 7 Parola riservata abstract Classi astratte (abstract) Una classe che dichiara l’esistenza di uno o più metodi ma non le loro implementazioni è chiamata classe astratta. Talvolta si ha la necessità di creare una classe che rappresenti certe caratteristiche fondamentali e dichiari certi metodi, ma non è possibile implementarli all’interno della classe stessa. Essi debbono essere implementati in una sotto-classe. Una classe astratta può certamente dichiarare ed implementare metodi normali, il cui comportamento è noto. Allo stesso modo una classe astratta può dichiarare ed usare variabili membro come tutte le altre classi. Le classi astratte non possono essere istanziate, ma si può dichiarare una variabile il cui tipo sia una classe astratta e poi riferirla in seguito ad una istanza di una classe concreta. Metodi astratti (abstract) I metodi che sono dichiarati ma non implementati, all’interno di una classe astratta, devono essere dichiarati abstract. Le classi che estendono una classe astratta devono implementare tutti i metodi dichiarati astratti nella classe genitore. Se non lo fanno devono essere dichiarate astratte. public abstract class Drawing { public abstract void drawDot(int x, int y); // NON IMPLEMENTATO public void drawLine(int x1, int y1, int x2, int y2){ // disegna usando ripetutamente il metodo drawDot(). } } Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 58 Caratteristiche avanzate delle classi - Interfacce Modulo 7 Una interfaccia è una variazione dell’idea di classe astratta. In una interfaccia tutti i metodi sono astratti. Si può simulare l’ereditarietà multipla implementando più interfacce. Nessuno dei metodi dichiarati può avere istruzioni ed in una interfaccia si possono dichiarare solo variabili di tipo static final. Una interfaccia dà solo l’impressione di aggirare la regola della singola ereditarietà. Mentre una classe estende solo una singola classe, essa può implementare tute le interfacce che servono. Quando una classe implementa una particolare interfaccia, essa deve implementare tutti i metodi dichiarati in quella interfaccia. In questo modo è possibile chiamare i metodi dell’interfaccia su qualsiasi oggetto della classe che implementa quella interfaccia. Le interfacce servono a: Dichiarare i metodi che una o più classi devono poi implementare. Dichiarare una interfaccia di programmazione (API) senza però che sia nota la modalità di esecuzione dei suoi metodi (può essere utile nella distribuzione di un package di classi ad altri sviluppatori). Associare somiglianze fra classi diverse senza che siano per forza messe in relazione fra loro. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 59 Wrapper Classes (classi involucro) Modulo 7 In Java gli unici tipi di dato che non sono considerati oggetto sono i tipi di dato primitivi. In quanto tali però essi non dispongono né di metodi né di proprietà. Allora Java fornisce alcune wrapper classes per manipolare i tipi di dato primitivi come se fossero oggetti. Le wrapper classes sono utili per convertire fra loro tipi di dati primitivi tramite i numerosi metodi disponibili. int x = Integer.valueOf(str).intValue(); Ignazio Testoni Tipo primitivo Wrapper Class boolean Boolean byte Byte char Character short Short int Integer long Long float Float double Double Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 60 Modulo 7 Collection Framework Una collection (o un container) è un singolo oggetto che rappresenta un gruppo di altri oggetti che formano i suoi elementi. Classi di tipo collection sono Vector, Bits, BitSet, Stack, Hashtable, LinkedList. Le Collection API comprendono interfacce che considerano gli oggetto come: Collection – Gruppo di oggetti senza ordine specifico; Set – Gruppo di oggetti senza duplicati; List – Gruppo di oggetti ordinati, la duplicazione è permessa. Es: Vector() -> prevede metodi per lavorare con array dinamici di vari tipi di elementi. Metodi: 1. 2. 3. 4. 5. 6. 7. 8. public int size(); public boolean contains(Object obj); public int indexOf(Object obj); public synchronized Object elementAt(int index); public synchronized void setElementAt(Object obj, int index); public synchronized void removeElementAt(int index); public synchronized void addElement(Object obj); ... ... Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 61 Modulo 7 Collection Framework A partire dalla versione 5 del JDK sono stati aggiunti tre nuovi meccanismi inerenti il cosiddetto Collection Framework. Generics – ulteriori controlli in fase di compilazione per le classi collections che eliminano la necessità di effettuare il cast in fase di lettura degli elementi dalle collections. Ciclo for avanzato – elimina la necessità degli iteratori espliciti quando si itera attraverso gli elementi di una collection. Autoboxing/unboxing – converte automaticamente i tipi primitivi (per esempio int) nella loro wrapper class (Integer) nel momento in cui li si inserisce in una collection, e converte le istanze delle wrapper class dei loro corrispondenti tipi primitivi quando li si estrae dalla collection. Vector<Integer>vector = new Vector<Integer>(); // Generics vector.add(new Integer(1)); vector.add(2); // Autoboxing vector.add(3); vector.add(3); Iterator i = vector.iterator(); for(int j=0; j<vector.size();j++){ Integer n = vector.elementAt(j); // Casting non necessario System.out.println(n); // Unboxing } for(Integer n:vector) { // Ciclo for avanzato System.out.println(n); } Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 62 Modulo 8: Eccezioni (Exceptions) Modulo 8 Introduzione: In Java la classe Exception definisce semplici condizioni di errore che i programmi potrebbero incontrare. Piuttosto che lasciare il programma terminare, si può fare in modo di gestire le eccezioni e continuare l’esecuzione del programma. Per esempio si può generare una eccezione quando: Un file che si tenta di aprire non esiste La connessione di rete non è più disponibile Gli operandi da manipolare hanno valori in un intervallo non più lecito Si tenta di accedere ad una classe il cui file per qualche motivo è mancante 1. public class HelloWorld{ 2. public static void main (String args []){ 3. int i=0; 4. String greetings [] = {“Hello World!”, “No, I Mean it!”, 5. “HELLO WORLD!”}; 6. while( i < 4 ){ 7. System.out.println(greetings[i]); 8. i++; 9. } 10. } 11. } Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 63 Modulo 8 Eccezioni (Exceptions) Il risultato dell’esecuzione del programma precedente è: C:\Documenti\JavaCourse>java HelloWorld Hello World! No, I Mean it! HELLO WORLD! Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException at HelloWorld.main(HelloWorld.java:7) La possibilità della gestione delle eccezioni consente ad un programma di catturarle, maneggiarle opportunamente e continuare l’esecuzione. Essa è strutturata in maniera tale che gli errori a runtime non lasciano che il programma fuoriesca dal normale flusso di esecuzione. Le eccezioni sono gestite nello stesso istante in cui avvengono, tramite blocchi di istruzioni separati, associati al normale codice per l’esecuzione del programma. Istruzioni try e catch Per maneggiare una particolare eccezione, includere all’interno di un blocco try il codice opportuno, e creare una lista di blocchi catch aggiuntivi, uno per ogni possibile eccezione che può essere generata. Se, durante l’esecuzione del blocco di istruzioni try, viene generata una delle eccezioni corrispondente ad una di quelle listate nelle istruzioni catch, il relativo codice sarà eseguito per gestire l’eccezione. E’ possibile inserire più di un blocco catch affinché si possano gestire tipi di errori diversi. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 64 Modulo 8 Eccezioni (Exceptions) Istruzioni try e catch Esempio HelloWorld. 1. public class HelloWorld{ 2. public static void main (String args []){ 3. int i=0; 4. String greetings [] = {“Hello World!”, “No, I Mean it!”, 5. “HELLO WORLD!”}; 6. while( i < 4 ){ 7. try{ 8. System.out.println(greetings[i]); 9. }catch(ArrayIndexOutOfBoundsException ex){ 10. System.out.println(“Error: greetings size is < ”+i); 11. } 12. i++; 13. } 14. } 15. } C:\Documenti\JavaCourse>java HelloWorld Hello World! No, I Mean it! HELLO WORLD! Error: greetings size is < 3 Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 65 Modulo 8 Eccezioni (Exceptions) In Java esistono tre ampie categorie di eccezioni. La classe java.lang.Throwable funge da classe genitore per tutti gli oggetti ti tipo Exception che possono essere lanciati e catturati usando il meccanismo di gestione delle eccezioni. I metodi definiti nella classe Throwable recuperano il messaggio di errore associato con l’eccezione e stampano lo stack trace (tracciamento) che mostra dove l’eccezione è avvenuta. Le tre sottoclassi fondamentali di Throwable sono: Error, Exception, and RunTimeException. Exception Categories Throwable Error VirtualMachineError Exception AWTError RunTimeException IOException OutOfMemoryError ArithmeticException EOFException StackOverflowError NullPointerException ............ ............ FileNotFoundExcption IndexOutOfBoundException Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 66 Modulo 8 Eccezioni (Exceptions) La regola Gestire o Dichiarare (una eccezione) Per caldeggiare la scrittura di codice robusto, Java richiede che se avviene una eccezione mentre un metodo si trova sullo stack (cioè è stato invocato), il chiamante del metodo deve determinare quale azione intraprendere in caso di eccezione. Per soddisfare queste richieste il programmatore può fare le seguenti due scelte: Lasciare che il metodo che ha generato l’eccezione la gestisca includendo nel suo codice i blocchi try{} catch(){}. In questo modo l’eccezione è gestita completamente, anche se il blocco relativo al catch è vuoto. Fare in modo che il metodo che ha generato l’eccezione non la gestisca rilanciandola indietro al metodo chiamante. Per fare questo è necessario marcare la dichiarazione del metodo con la parola riservata throws come mostrato di seguito: public void callsTroubleSome() throws IOException La parola throws può essere seguita da uno o più nomi di eccezioni separati da virgole che il metodo può rilanciare al suo chiamante. La scelta di gestire o dichiarare una eccezione dipende da cosa il programmatore ritiene più opportuno. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 67 Modulo 9 Modulo 9: Realizzare una GUI Package AWT (Abstract Windowing Toolkit) Fornisce i componenti grafici di base usati in tutte le applicazioni Java per realizzare le GUI (Graphic User Interface). Contiene delle classi che possono essere estese, e le loro proprietà ereditate. Assicura che ogni componente GUI visualizzato sullo schermo sia una sottoclasse della classe astratta Component. Comprende Container, una classe astratta, sottoclasse di Component ed include due sottoclassi: 1. Panel 2. Window AWT fornisce la possibilità di creare interfacce grafiche il cui aspetto è molto simile fra le diverse piattaforme esistenti. Ogni componente GUI che appare sullo schermo è una sottoclasse della classe astratta Component. Ovvero, ogni oggetto grafico che estende la classe Component condivide con gli altri tutti i metodi e le variabili di classe che consentono loro di lavorare. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 68 Modulo 9 Il package java.awt The java.awt Package java.lang.Object Panel Applet BorderLayout CardLayout CheckboxGroup Color Dimension Event Font GridLayout Toolkit GridbagLayout Component Button Canvas CheckBox Choice Container Label List TextComponent Window Dialog ScrollPane TextArea TextField Frame FileDialog MenuBar Menu MenuItem Menu Popup Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 69 Modulo 9 Containers Vi sono due tipi principali di containers: Window e Panel. Una Window è una finestra nativa visualizzabile sullo schermo, indipendente da altri contenitori. Due sono le sottoclassi più importanti: Frame e Dialog. 1. Frame è una finestra che contiene un titolo ed ha gli angoli per ridimensionarla. 2. Dialog non ha barra per i menu, si può muoverla ma non ridimensionarla. Un Panel è contenuto sempre in un altro Container, o in una Applet. Un Panel identifica una area rettangolare in cui disporre altri componenti. Panel, per poter essere visualizzato, deve essere disposto dentro una Window (o una sua sottoclasse). Panel Frame Frame Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 70 Modulo 9 Realizzazione di una GUI La posizione e la dimensione dei componenti in un Container è determinata da un layout manager. Quando in un Container si deve posizionare un componente, interviene per farlo il layout manager. Lo stesso avviene quando è necessario determinare la dimensione di un componente. Il layout manager possiede il controllo completo su tutti i componenti contenuti nel Container. Esso è responsabile del calcolo e della definizione delle dimensioni ottimali nel contesto delle particolari dimensioni dello schermo. Al contrario è anche possibile disabilitare il layout manager ed avere in proprio il controllo completo dei componenti invocando il metodo: container.setLayout(null); In questo caso, per posizionare gli oggetti è necessario usare i metodi setLocation(), setSize(), o setBounds() sui componenti che del container. Bisogna considerare in questo caso che il risultato potrebbe differire fra una piattaforma e l’altra a causa delle differenze nei vari sistemi di finestre e dimensione dei font. L’ approccio migliore è quello di usare un Layout Manager. Java è provvisto dei seguenti layout manager: FlowLayout – layout manager predefinito per Panel ed Applet. BorderLayout – layout manager predefinito per Window e Panel. GridLayout CardLayout GridBagLayout Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 71 Flow Layout Manager: un esempio ExGui.java import java.awt.*; new Frame(“GUI Example”) Questo metodo crea una istanza della classe Frame. Se non diversamente specificato Frame ha dimensioni 0x0 e non è visibile. public class ExGui{ private Frame f; private Button b1; private Button b2; public void go(){ f = new Frame("GUI Example"); f.setLayout(new FlowLayout()); b1 = new Button("Press Me"); b2 = new Button("Don't Press Me"); f.add(b1); f.add(b2); f.pack(); f.setVisible(true); } public static void main(String [] s){ ExGui guiWin = new ExGui(); guiWin.go(); } } Ignazio Testoni Modulo 9 f.setLayout(new FlowLayout); Questo metodo crea una istanza della del layout manager flow layout e lo installa nel Frame. Il FlowLayout manager è il più semplice per AWT e dispone i componenti orizzontalmente o verticalmente. f.add(b1); Indica al Frame f (che è un container) che deve accludere in sé il componente b1. La dimensione e posizione di b1 sono sotto il controllo del layout manager del Frame f. f.pack(); Indica al frame di disporre i propri componenti in maniera tale da renderli tutti visibili ed in ordine. Per determinare quali dimensioni usare per i componenti, f.pack() interroga il proprio layout manager, responsabile per le dimensioni e posizione di tutti i componenti contenuti nel Frame. Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 72 Flow Layout Manager: un esempio Modulo 9 Il FlowLayout usato in questo esempio posiziona i componenti riga dopo riga. Quando lo spazio disponibile su una riga si esaurisce i nuovi componenti vengono disposti sul una nuova riga successiva. Il FlowLayout, unlike other layout managers, does not constrain the size of the components it manages, but instead allows them to have preferred size. Gli argomenti del costruttore di FlowLayout consentono di specificare se allinerae gli elementi da sinistra verso destra o viceversa oppure di tenerli centrati. Si può specificare lo spazio vuoto minimo fra i componenti. Se l’area gestita da un FlowLayout viene ridimensionata dall’utente, il layout può cambiare. FlowLayout: ridimensionamento Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 73 Modulo 9 Grid Layout Manager Il GridLayout manager un po’ più di flessibilità per disporre i componenti. I componenti sono disposti in una matrice con un certo numero di righe e di colonne. I componenti riempiono le celle definite dal manager. La posizione relativa dei componenti non cambia se l’intera area è ridimensionata. Cambia solo la dimensione dei singoli componenti. Il GridLayout manager ignora sempre la dimensione ottimale dei componenti. L’altezza e la larghezza delle celle è uguale per tutte ed è determinata dividendo l’altezza e la larghezza totale disponibile per il numero di righe e di colonne. import java.awt.*; public class GridExample{ GridLayout gl = new GridLayout(4,3); public GridExample(){ Frame f = new Frame("GridLayout Example"); f.setLayout(gl); for(int c=9;c>=0;c--){ f.add(new Button(""+c)); } f.add(new Button("+/-")); f.add(new Button(",")); f.pack(); f.setVisible(true); } public static void main(String [] s){ GridExample g = new GridExample(); } } Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 74 Modulo 10: Gestione degli eventi Modulo 10 Quando un utente compie un’azione su una interfaccia grafica (cliccare sul mouse, premere un tasto, ingrandire una finestra, etc.), viene generato un Evento. Gli Eventi sono modellizzati tramite degli oggetti che descrivono che cosa è accaduto. Per descrivere le varie categorie di azioni che un utente può provocare, esiste in java una molteplicità di classi Event già predefinite. I soggetti coinvolti nella generazione e nella gestione di un evento sono: Event – Oggetti che descrivono che cosa è accaduto. Event sources – Oggetti che generano gli eventi. Un esempio di Event source è un oggetto di tipo Button che genera un evento di tipo ActionEvent che contiene informazioni sull’evento. ActionEvent possiede i metodi: getActionCommand() – restituisce un oggetto String associato all’azione compiuta getModifiers() – restituisce eventuali tasti modificatori premuti (ctrl, alt, shift …). Event handlers – Uno o più metodi che ricevono un oggetto di tipo evento, lo decifrano e consentono l’interazione con l’utente. Nel caso di ActionEvent il metodo ad esso associato per gestire l’evento è: actionPerformed() – contiene le istruzioni da eseguire in seguito alla generazione dell’evento. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 75 Modulo 10 Delegation Model: i Listener Il meccanismo chiamato “Delegation Model” consiste nel delegare una classe opportuna alla gestione dell’evento generato. Cioè, il componente che ha originato l’evento lo propaga ad una o più classi registrate dette listener. Ogni listener deve essere registrato nell’oggetto che genera l’evento. I listener contengono gli event handlers che ricevono l’evento generato e lo processano eseguendo le azioni necessarie. I listener devono implementare una interfaccia di tipo EventListener o una sua sottoclasse. Gli oggetti di tipo evento sono propagati esclusivamente ai listener registrati. Ogni tipo di evento possiede una corrispondente interfaccia di tipo listener che obbliga la classe che la implementa a definire tutti i suoi metodi. Se un componente genera un evento ma non ha nessun listener registrato, l’evento non viene propagato. Event handler relativo a Panel e Frame Evento di tipo ActionEvent public void actionPerformed (ActionEvent e) { frame.close(); // Chiude la finestra Action handler } Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 76 Delegation Model: un esempio Modulo 10 package corso; // TestButton.java import java.awt.*; La classe Button ha il metodo addActionListener() public class TestButton { che consente al listener di essere registrato. public TestButton() { L’interfaccia ActionListener definisce un solo } metodo, actionPerformed(), che riceve un evento public static void main(String [] s){ ActionEvent. Frame frame = new Frame("Test"); Button button = new Button("Premere!"); Il listener registrato deve implementare button.addActionListener(new ButtonHandler()); l’interfaccia ActionListener. frame.add(button); frame.pack(); frame.setVisible(true); } } package corso; // ButtonHandler.java Action handler import java.awt.event.*; Un click sul Button genera un ActionEvent public class ButtonHandler implements ActionListener { che viene ricevuto da actionPerformed(), public ButtonHandler() { metodo di ButtonHandler che è registrato come listener sul Button. } public final void actionPerformed(final ActionEvent actionEvent) { Il metodo getActionCommand() della classe System.out.println("Attenzione! Evento di tipo Action!"); ActionEvent restituisce il nome del comando System.out.println("Il pulsante premuto e':"+ associato all’azione. Nel caso di Button esso actionEvent.getActionCommand()+"\n"); restituisce la sua etichetta (label). } } Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 77 Modulo 10 Tipologie di eventi ed interfacce Categoria Interfaccia Metodi Action ActionListener actionPerformed(ActionEvent) Item ItemListener itemStateChanged(ItemEvent) Mouse motion MouseMotionListener mouseDragged(MouseEvent) mouseMoved(MouseEvent) Mouse button MouseListener mousePressed(MouseEvent) mouseReleased(MouseEvent) mouseEntered(MouseEvent) mouseExited(MouseEvent) mouseClicked(MouseEvent) Key KeyListener keyPressed(KeyEvent) keyReleased(KeyEvent) keyTyped(KeyEvent) Focus FocusListener focusGained(FocusEvent) focusLost(FocusEvent) Window WindowListener windowClosing(WindowEvent) windowOpened(WindowEvent) windowIconified(WindowEvent) windowDeiconified(WindowEvent) windowClosed(WindowEvent) windowActivated(WindowEvent) windowDeactivated(WindowEvent) Text TextListener textValueChanged(TextEvent) Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 78 Modulo 10 Gli Event Adapters Ogni volta che si implementa un’interfaccia bisogna necessariamente implementare tutti i suoi metodi. Naturalmente questo vale anche per i listener. A volte può essere piuttosto noioso implementare diversi metodi anche se poi non li si utilizza. Per esempio questo accade frequentemente con le interfacce MouseListener e WindowListener che dichiarano rispettivamente 5 e 7 metodi per la gestione dei vari eventi . Allo scopo di facilitare il programmatore, java fornisce alcune classi che implementano automaticamente tutti i metodi della relativa interfaccia dichiarata. Queste classi sono dette Adapter classes e ne esiste una per ogni listener che dichiara più di un metodo. Per esempio: MouseAdapter WindowAdapter ComponentAdapter FocusAdapter import java.awt.*; Mouse click handler import java.awt.event.*; public class MouseClickHandler extends MouseAdapter { // Serve solo la gestione del click public final void mouseClicked(MouseEvent mouseEvent) { // Overriding del metodo omonimo della classe MouseAdapter } } Per poterle utilizzare basta creare una nuova classe che estende l’adapter opportuno. A questo punto serve solo reimplementare, attraverso l’overriding, il metodo o i metodi (event handler) che si intende sfruttare. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 79 Modulo 11 Modulo 11: La calcolatrice Tramite lo studio di questo programma vedremo applicati tutti i principali argomenti trattati nel presente corso. Il programma si basa sulla tecnica Model-View-Control e consta delle seguenti classi: 1. Calculator.java => View 2. EventHandler.java => Control 3. Operation.java 4. OperationDivide.java 5. OperationMultiply.java 6. OperationSubtract.java 7. OperationSum.java La classe Calculator si occupa della creazione dell’interfaccia grafica e contiene il metodo main(String [] s). La Classe EventHandler si occupa della gestione completa di tutti gli eventi generati dalla GUI. La classe astratta Operation rappresenta una delle 4 operazioni a due operandi (+,-,*,/) e viene estesa dalle quattro classi Operation rimanenti. In funzione della operazione selezionata tramite la GUI, il programma esegue il metodo getResult() della classe corrispondente (polimorfismo). Le rimanenti operazioni che lavorano solo su un operando effettuano il calcolo nell’istante in cui viene premuto il relativo pulsante. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 80 La GUI Modulo 11 L’interfaccia grafica consiste in un Frame che ha un BorderLayout come layout manager. Il Frame contiene al suo interno: • Una Label che ne rappresenta il display disposto nella posizione NORTH • Un Panel contenente la Label per la memoria ed i tre pulsanti per azzerare il display, disposto nella posizione CENTER Il Panel a sua volta ha un FlowLayout come layout manager. • Un Panel contenente il resto dei pulsanti disposto nella posizione SOUTH. Il Panel a sua volta ha un GridLayout come layout manager. I pulsanti nel GridLayout sono contenuti in una struttura dati di tipo Hashtable con una associazione chiave – valore. La chiave è rappresentata dall’etichetta, il valore è il corrispondente oggetto Button. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 81 Modulo 11 EventHandler La classe EventHandler estende WindowAdapter ed implementa ActionListener. Estendere WindowAdapter consente di dover reimplementare solo uno dei 7 metodi dichiarati, cioè windowClosing(), per poter chiudere il programma chiudendone semplicemente la finestra cliccando con il mouse sul tasto di chiusura della finestra stessa. L’implementazione dell’interfaccia ActionListener ci obbliga a dover definire ed implementare il metodo actionPerformed() dove sono descritte tutte le operazioni da effettuare in corrispondenza della pressione di ciascun Button. La classe EventHandler viene registrata come Listener sia nel Frame per gli eventi generati dal Frame sia in ciascun Button per gli eventi generati da tutti i Button. La stringa actionCommand contiene l’etichetta del pulsante che è stato premuto. In funzione del valore di actionCommand vengono eseguite le istruzioni opportune. Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007 82 Java programming Language Continua … Ignazio Testoni Ordine degli Ingegneri Provincia di Catania 29 giugno – 7 luglio 2007