Corso Java

5,428 views

Published on

Published in: Technology
0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
5,428
On SlideShare
0
From Embeds
0
Number of Embeds
1,835
Actions
Shares
0
Downloads
0
Comments
0
Likes
6
Embeds 0
No embeds

No notes for slide

Corso Java

  1. 1. <ul><li>Caratteristiche di Java </li></ul><ul><li>Autore : Giuseppe Dell’Abate </li></ul>
  2. 2. <ul><li>1987 Progetto per software di dispositivi elettronici </li></ul><ul><li>1988 James Gosling abbandonò il C++ e creò Oak </li></ul><ul><li>1992 FirstPerson, Inc., succursale della Sun, commercializza OAK: nasce Java </li></ul><ul><li>1994 creazione di browser Web Runner poi HotJava </li></ul><ul><li>1995 Netscape integra Java, in seguito anche Microsoft </li></ul>
  3. 3. <ul><li>Orientato agli oggetti </li></ul><ul><li>Semplice </li></ul><ul><li>Indipendente dalla piattaforma </li></ul><ul><li>Portabile </li></ul><ul><li>Sicuro </li></ul><ul><li>Multithreading </li></ul><ul><li>Dinamico </li></ul>
  4. 4. <ul><li>Caratteristiche paradigma ad oggetti: </li></ul><ul><ul><ul><li>Ereditarietà </li></ul></ul></ul><ul><ul><ul><li>Incapsulamento </li></ul></ul></ul><ul><ul><ul><li>Poliformismo </li></ul></ul></ul><ul><li>Creazione di TIPI personalizzati </li></ul><ul><li>Basato sulle classi NON sugli oggetti </li></ul><ul><li>Ma cos’è una classe? ed un oggetto? </li></ul>
  5. 5. <ul><li>Rispetto al C++ </li></ul><ul><ul><li>Non è object based ma object oriented (è ad oggetti puro) </li></ul></ul><ul><ul><li>Non ha l’aritmetica dei puntatori (ma passaggi per valore) </li></ul></ul><ul><ul><li>Non deve deallocare la memoria (c’è la garbage collector) </li></ul></ul><ul><ul><li>Non ha ereditarietà multipla (ma singola) </li></ul></ul>
  6. 6. <ul><li>Indipendentemente dalla architettura hardware e dal sistema operativo, la Java Virtual Machine interpreta il bytecode e lo esegue </li></ul>
  7. 7. <ul><li>Tipi primitivi mantengono le loro dimensioni in tutte le piattaforma grazie alla JVM </li></ul>
  8. 8. <ul><li>Le classi sono collegate solo quando richiesto </li></ul><ul><li>Possono provenire dal file system locale così come dalla rete </li></ul><ul><li>Il codice viene verificato prima di essere passato all’interprete per l’esecuzione. </li></ul><ul><li>E’ possibile aggiungere nuovi metodi e variabili di istanza ad una classe, senza dover ricompilare l’intera applicazione </li></ul>
  9. 9. <ul><li>elaborazioni simultanee in un ambiente a singolo processo </li></ul><ul><li>la gestione dei thread in genere e di tipo preemptive </li></ul><ul><li>Nei sistemi in cui la gestione è non preemptive Java fornisce il metodo yield() che dà, ad un altro thread, la possibilità di essere comunque eseguito </li></ul><ul><li>i metodi dichiarati synchronized non possono essere eseguiti simultaneamente da più thread; </li></ul>
  10. 10. <ul><li>Operazioni eseguite dal compilatore: </li></ul><ul><ul><li>controlli di errori di codifica </li></ul></ul><ul><ul><li>le dichiarazioni di tipo esplicite e non implicite </li></ul></ul><ul><ul><li>le classi sono inserite in un namespace per gestire la sicurezza </li></ul></ul><ul><li>Operazioni eseguite dal sistema run-time: </li></ul><ul><ul><li>L’allocazione della memoria dipende dalla piattaforma </li></ul></ul><ul><ul><li>Il puntatore alla memoria non esiste ma esistono riferimenti simbolici, risolti in indirizzi di memoria reali in fase di esecuzione </li></ul></ul><ul><ul><li>I tipi sono noti e corretti </li></ul></ul><ul><li>Operazioni eseguite dal compilatore e dal sistema run-time : </li></ul><ul><ul><li>strati di difesa contro il codice che può essere potenzialmente pericoloso </li></ul></ul>
  11. 12. <ul><li>Package, interfacce e classi astratte </li></ul><ul><li>Giuseppe Dell’Abate </li></ul>
  12. 13. <ul><li>Le classi e le interfacce Java sono organizzate in package </li></ul><ul><li>Rappresentano dei pacchetti in cui vengono inglobate le classi che presentano: </li></ul><ul><ul><li>caratteristiche in comune (java.io) </li></ul></ul><ul><ul><li>appartengono allo stesso progetto (it.fastweb.crm.om.) </li></ul></ul><ul><ul><li>vengono prodotte dalla stessa societa (it.fastweb) </li></ul></ul>
  13. 15. <ul><li>I packages sono identificati dall'istruzione package. </li></ul><ul><li>Essa deve apparire come la prima istruzione nel file del codice sorgente. </li></ul><ul><li>Esempio: package mioPackage; public class MiaClasse { ........... } </li></ul>
  14. 16. <ul><li>Ci sono tre modi per utilizzare un membro (pubblico) definito in un package: </li></ul><ul><ul><li>attraverso il suo nome completo </li></ul></ul><ul><ul><li>importandolo </li></ul></ul><ul><ul><li>importando l’intero package a cui il membro appartiene </li></ul></ul>
  15. 17. <ul><li>Esempio: </li></ul><ul><li>public class Classe { mioPackage. MiaClasse fg; </li></ul><ul><li>} </li></ul><ul><li>Indichiamo: </li></ul><ul><ul><li>il nome del package </li></ul></ul><ul><ul><li>l’operatore . che ci permette di entrare internamente nel package </li></ul></ul><ul><ul><li>il nome della classe </li></ul></ul>
  16. 18. <ul><li>Esempio: </li></ul><ul><li>import mioPackage.MiaClasse; </li></ul><ul><li>public class Classe { MiaClasse fg; </li></ul><ul><li>} </li></ul><ul><li>Indichiamo: </li></ul><ul><ul><li>import seguito del nome del package seguito dalla classe </li></ul></ul><ul><ul><li>dichiariamo l’oggetto fg nel modo classico </li></ul></ul>
  17. 19. <ul><li>Esempio: </li></ul><ul><li>import mioPackage.*; </li></ul><ul><li>public class Classe { MiaClasse fg; </li></ul><ul><li>} </li></ul><ul><li>Indichiamo: </li></ul><ul><ul><li>import di tutte le classi del package attraverso il simbolo * </li></ul></ul><ul><ul><li>dichiariamo l’oggetto fg </li></ul></ul>
  18. 20. <ul><li>Una classe appartenente ad un package deve essere salvata all’interno dell’albero che viene definito dal path del package: </li></ul><ul><li>Esempio: </li></ul><ul><ul><li>package mioPackage.mioEsempio </li></ul></ul><ul><ul><li>class MiaCLasse {...} </li></ul></ul><ul><li>la classe MiaClasse.java deve essere salvata nelle cartelle mioPackagemioEsempio </li></ul><ul><ul><li>c:mioPackagemioEsempio>dir </li></ul></ul><ul><ul><li>MiaClasse.java </li></ul></ul><ul><li>In sede di compilazione si dovrà accedere dall’interno della cartella dove risiedono i file *.java </li></ul><ul><ul><li>c:mioPackagemioEsempio> javac MiaClasse.java </li></ul></ul><ul><ul><li>c:mioPackagemioEsempio>dir </li></ul></ul><ul><ul><li>MiaClasse.java </li></ul></ul><ul><ul><li>MiaClasse.class </li></ul></ul>
  19. 21. <ul><li>In sede di esecuzione di una classe contenuta in un package occorre lanciare la classe (che contiene il main) dall’esterno della prima cartella che delimita il package </li></ul><ul><li>Esempio: </li></ul><ul><ul><li>C:mioPackagemioEsempio>dir </li></ul></ul><ul><ul><li>MiaClasse.java </li></ul></ul><ul><ul><li>MiaClasse.class </li></ul></ul><ul><ul><li>c:>java mioPackage.mioEsempio.MiaClasse </li></ul></ul>
  20. 22. <ul><li>Una classe astratta può definire metodi astratti, ossia metodi di cui non viene fornita l’implementazione e prevedere, in senso generico, quali comportamenti (metodi) dovranno caratterizzare le sue classi discendenti </li></ul><ul><li>Le definizioni esatte dei comportamenti verranno però effettuate dalle classi eredi (istanziabili), cosicché possano riflettere le loro specifiche esigenze </li></ul><ul><li>Una classe astratta può pero contenere anche metodi non astratti </li></ul>
  21. 23. <ul><li>abstract class MiaSuperClasseAstratta { void mioMetodoImplementato(...) {…implementazione}; abstract void mioMetodo(...); } </li></ul><ul><li>class MiaClasseErede extends MiaSuperClasseAstratta { void mioMetodo(...) { // implementazione } } </li></ul><ul><li>Occorre sempre implementare i metodi astratti nella classe erede altrimenti si genera un errore in compile-time </li></ul>
  22. 24. <ul><li>Un’interfaccia è un insieme di definizioni di metodi (senza implementazione) e (eventualmente) di dichiarazioni di costanti </li></ul><ul><li>In Java, le interfacce rappresentano un mezzo per permettere anche a oggetti tra loro scorrelati di interagire l’uno con l’altro </li></ul><ul><li>Esempio: </li></ul><ul><li>public interface MiaInterfaccia { int UNA_COSTANTE_INTERA = 100; String UNA_COSTANTE_STRINGA = &quot;ciao&quot;; void metodo1(int a); char metodo2(String s, long l); } </li></ul><ul><li>Nelle interfacce possiamo definire solo costanti di classe e metodi di istanza astratti da implementare. Entrambi saranno public. </li></ul>
  23. 25. <ul><li>Attraverso le interfacce è possibile mediare il limite della ereditarietà singola di Java implementando più interfacce </li></ul><ul><li>Tecniche utilizzabili </li></ul><ul><ul><li>forwarding </li></ul></ul><ul><ul><li>eredita a diamante </li></ul></ul>
  24. 26. <ul><li>Le interfacce possono ereditare da altre interfacce, anche da più di una contemporaneamente (quindi tra interfacce è ammessa l’eredità multipla) </li></ul><ul><li>Esempio: interface I extends I1, I2, ..., In { ......... } dove I1, I2, ..., In sono interfacce I eredita tutte le costanti e tutti i metodi di I1, I2, ..., In </li></ul><ul><li>Una classe che implementi un’interfaccia I deve implementare anche i metodi delle interfacce da cui I eredita </li></ul>
  25. 27. <ul><li>Le interfacce </li></ul><ul><ul><li>Ci forniscono una forma di eredità multipla </li></ul></ul><ul><ul><li>Ci permettono di dichiarare metodi di istanza e proprietà static final </li></ul></ul><ul><ul><li>Possiamo dichiarare solo metodi astratti </li></ul></ul><ul><ul><li>Non possiamo fissare livelli di accesso diversi da public </li></ul></ul><ul><ul><li>Non possiamo istanziare una interfaccia </li></ul></ul>
  26. 28. <ul><li>Programmare in Java </li></ul><ul><li>Giuseppe Dell’Abate </li></ul>
  27. 29. <ul><li>Applicazione </li></ul><ul><li>Applet </li></ul><ul><li>Interfaccia utente </li></ul><ul><ul><li>GUI Java - sessione DOS </li></ul></ul><ul><ul><li>Browser </li></ul></ul>
  28. 30. <ul><li>Classe Java è composta da: </li></ul><ul><ul><li>metodi speciali(costruttore, main) </li></ul></ul><ul><ul><li>metodi (funzioni, procedure) </li></ul></ul><ul><ul><li>proprietà (variabile, costante) </li></ul></ul>
  29. 31. <ul><li>Metodo della classe che viene eseguita per avviare l’applicazione. </li></ul><ul><li>Esiste un solo metodo main </li></ul><ul><li>Il metodo main viene usato solo per le applicazioni e non per le Applet o le servlet. </li></ul><ul><ul><li>public static void main(String [] args) { //blocco di istruzioni </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>public : è necessario che sia accessibile per poter avviare la classe </li></ul></ul><ul><ul><li>static : è un metodo di classe </li></ul></ul><ul><ul><li>void : non restituisce nessun valore </li></ul></ul><ul><ul><li>main : nome del metodo principale, </li></ul></ul><ul><ul><li>String [] args : Array di stringhe usato come parametro (obbligatorio) </li></ul></ul><ul><ul><li>blocco di istruzion i: sono le istruzioni che implementiamo </li></ul></ul>
  30. 32. <ul><li>Metodo che viene eseguita quando si istanzia una classe. </li></ul><ul><ul><ul><li>public class MiaClasse public MiaClasse() { //blocco di istruzioni } </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>public : è necessario che sia accessibile per instanziare la classe </li></ul></ul><ul><ul><li>MiaClasse : ha lo stesso nome della classe </li></ul></ul><ul><ul><li>blocco di istruzioni : sono le istruzioni che implementiamo </li></ul></ul><ul><li>possono esistere più metodi costruttori con diversi tipi e quantità di parametri (overloading) </li></ul>
  31. 33. <ul><li>I metodi sono dei blocchi di istruzioni definiti in una classe </li></ul><ul><li>Sono di due tipologie </li></ul><ul><ul><li>funzione (elaborano i dati e restituiscono un valore) </li></ul></ul><ul><ul><li>procedure (eseguono la procedura e non restituiscono un valore) </li></ul></ul>
  32. 34. <ul><li>Elaborano eventuali parametri e restituiscono un risultato </li></ul><ul><li>int moltiplicavalori(int a, int b) { risultato= a * b; return(risultato); } </li></ul><ul><ul><li>int è il tipo di valore che la funzione restituirà(quindi il tipo della variabile risultato); </li></ul></ul><ul><ul><li>moltiplicavalori è il nome della funzione; </li></ul></ul><ul><ul><li>all'interno delle parentesi tonde troviamo i due parametri che forniamo alla funzione con i loro relativi tipi </li></ul></ul><ul><ul><li>all'interno delle parentesi graffe troviamo il blocco di istruzioni della funzione </li></ul></ul><ul><ul><li>l'istruzione return (...) è quella che permette alla funzione di restituire il valore risultato. Le istruzioni che seguono l'istruzione return vengono ignorate </li></ul></ul>
  33. 35. <ul><li>Elaborano eventuali parametri e non restituiscono un valore. Servono per evitare di ripetere un blocco di codice </li></ul><ul><ul><li>void nomeMetodo(int a, int b) { System.out.println(a+” - “+b ); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>void (vuoto) indica che la funzione non restituira nessun valore ma eseguira solamente le istruzioni indicate </li></ul></ul><ul><ul><li>nomeMetodo è il nome della funzione; </li></ul></ul><ul><ul><li>all'interno delle parentesi tonde troviamo i due parametri che forniamo alla funzione con i loro relativi tipi </li></ul></ul><ul><ul><li>all'interno delle parentesi graffe troviamo il blocco di istruzioni della funzione </li></ul></ul><ul><ul><li>l'istruzione System.out.println(...) è quella che permette alla funzione di visualizzare i parametri passati </li></ul></ul>
  34. 36. <ul><li>Le proprietà sono collegate ai tipi , che posso essere : </li></ul><ul><ul><li>primitivi : si prestano ad un uso intuitivo </li></ul></ul><ul><ul><li>reference : fanno riferimento ad oggetti, array, ecc </li></ul></ul><ul><li>A seconda della modificabilità , possono essere. </li></ul><ul><ul><li>Costanti (variabili final): dati che non possono subire alcuna modifica </li></ul></ul><ul><ul><li>Variabili : dati suscettibili di modificazione </li></ul></ul><ul><li>A seconda della globalità possono essere: </li></ul><ul><ul><li>static : le modifiche apportate da un oggetto a questi dati si propagano a tutte le istanze di quell’oggetto </li></ul></ul><ul><ul><li>di istanza : le modifiche apportate non si ripercuotono alle altra istanze </li></ul></ul>
  35. 38. Per garantire la portabilità del Bytecodes da una piattaforma ad un’altra Java fissa le dimensioni di ogni dato primitivo
  36. 39. Java assegna ad ogni variabile un valore di default al momento della dichiarazione
  37. 40. <ul><li>Il tipo byte permette di operare su numeri compresi tra -128 e 127, che sono i numeri che è possibile rappresentare con cifre da 8 bit con segno </li></ul><ul><li>Il tipo short permette di trattare numeri a 16 bit, compresi tra -32768 e 32767: è in assoluto il formato meno usato in Java </li></ul><ul><li>Il tipo int è senza dubbio il tipo primitivo più usato, per ragioni di praticità e di efficienza. Può contenere qualunque numero intero compreso tra 2.147.483.647 e -2.147.483.648, ossia tutti i numeri rappresentabili con una cella di memoria a 32 bit con segno </li></ul><ul><li>Il tipo long a 64 bit, che permette di trattare numeri compresi tra -9.223.327.036.854.775.808 ed 9.223.327.036.854.775.807. è necessario post porre al numero la lettera 'L' </li></ul>
  38. 41. <ul><li>Il tipo float , a 32 bit, può contenere numeri positivi e negativi compresi tra 1.40129846432481707*10^-45 e 3.4282346638528860*10^38 </li></ul><ul><li>Il tipo double a 64 bit può lavorare su numeri positivi e negativi tra 4.94065655841246544*10^-324 e 1.79769313486231570*10^138 </li></ul><ul><ul><li>Nota: due numeri separati da un carattere 'e' (maiuscolo o minuscolo): il primo di questi numeri, detto mantissa, può contenere il punto decimale, mentre il secondo, l'esponente, deve per forza essere un intero. Il valore del numero viene calcolato moltiplicando la mantissa per 10 elevato alla potenza del valore dell'esponente </li></ul></ul><ul><li>float number = 1.56e3F; </li></ul><ul><li>double bigNumber = 5.23423e102; </li></ul>
  39. 42. <ul><li>Una variabile booleana può assumere solamente due valori: 'true' e 'false’ </li></ul><ul><li>boolean a = true; </li></ul><ul><li>boolean b = false; </li></ul><ul><li>Il ricorso agli operatori relazionali '==', '!=', '>', '<', '>=' e '<=', permette di assegnare ad una variabile booleana il valore di verità di un'espressione. Ad esempio: </li></ul><ul><li>boolean b = (a == 10); </li></ul><ul><li>assegna a b il valore di verità dell'espressione a == 10, che sarà 'true' se la variabile 'a' contiene il valore 10, 'false' in caso contrario </li></ul>
  40. 43. <ul><li>Il tipo char può contenere un carattere in formato Unicode che comprende decine di migliaia di caratteri, vale a dire gli alfabeti più diffusi nel mondo. </li></ul><ul><li>I valori da 0 a 127 corrispondono, per motivi di retro compatibilità, al set di caratteri ASCII </li></ul><ul><li>Il tipo char è un intero a 16 bit privo di segno: pertanto esso può assumere qualunque valore tra 0 e 65535 </li></ul><ul><li>char carattere1 = 'a'; </li></ul>
  41. 44. <ul><li>Il carattere speciale '' ha il ruolo di specificare alcuni caratteri che altrimenti non è possibile specificare con la tastiera </li></ul><ul><li>' ' nuova linea ' ' a capo 'f' nuova pagina ''' carattere apice '&quot;' carattere doppio apice 'apos; carattere backslash '' backspace ' ' carattere di tabulazione </li></ul>
  42. 45. <ul><li>Promozione: se la variabile destinazione è più capace di quella di partenza </li></ul><ul><ul><li>byte b = 100; short s = b; // promozione da byte a short int i = s; // promozione da short a int long l = i; // promozione da int a long </li></ul></ul><ul><li>Casting: se la variabile destinazione è meno capace di quella di partenza </li></ul><ul><ul><li>long l = 100; int i = (int)l; // cast da long a int short s = (short)i; // cast da int a short byte b = (byte)s; // cast da short a byte </li></ul></ul>
  43. 46. <ul><li>Il primo volo dell'Ariane 5 (Ariane 5 volo 501) svoltosi il 4 giugno 1996 fallì e il razzo si auto distrusse dopo 40 secondi dal lancio per via di un malfunzionamento del software di controllo, creato da uno dei più famosi bug della storia. </li></ul><ul><li>Un dato a 64 bit in virgola mobile venne convertito in un intero a 16 bit con segno, questa operazione causò una trap del processore (operazione errata): il numero in virgola mobile era troppo grande per poter essere rappresentato con un intero a 16 bit. </li></ul><ul><li>Motivi di efficienza avevano spinto i progettisti a disabilitare il controllo software (scritto in Ada) sulle trap, anche se altre conversioni simili nel codice erano corrette. </li></ul>
  44. 47. Java mette a disposizione del programmatore una serie di operatori utili
  45. 48. <ul><li>L’operatore di assegnamento “=” consente al programmatore, una volta definita una variabile, di assegnarle un valore. </li></ul><ul><li>Assegna il valore 5 alla destra dell’operatore alla variabile res1. </li></ul><ul><ul><li>int res1 = 5; </li></ul></ul><ul><li>Esegue l’espressione alla destra dell’operatore e ne assegna il risultato (15) a res1. </li></ul><ul><ul><li>int res1 = 5+10; </li></ul></ul>
  46. 49. Java mette a disposizione del programmatore una serie di operatori di assegnamento di tipo “shortcut”
  47. 50. Se si desidera effettuare un incremento di valore superiore ad 1, si può ricorrere all'operatore '+='; l'espressione x = x+10; può essere riscritta in questo modo x += 10; Gli operatori '++' e '--' possono precedere o seguire una variabile. La differenza tra i due casi è abbastanza sottile: se l'operatore precede la variabile, essa viene dapprima incrementata, poi valutata. Nel seguente esempio x = 10; y = ++x*2; la variabile x viene incrementata prima che venga calcolato il valore di y, che pertanto assume il valore 22. Al contrario x = 10; y = x++*2; la variabile x viene prima valutata, poi viene incrementata a 11. Pertanto y assumerà il valore 20, ossia 10 per 2.
  48. 51. Java supporta tutti i più comuni operatori aritmetici (somma, sottrazione, moltiplicazione, divisione e modulo). Gli operatori binari (ovvero operatori che necessitano di due operandi) sono cinque e sono schematizzati nella tabella seguente:
  49. 52. Gli operatori relazionali servono ad effettuare un confronto tra valori producendo come risultato di ritorno un valore booleano (true o false) come prodotto del confronto. Nella tabella sono riassunti gli operatori ed il loro significato.
  50. 53. Gli operatori di shift bit a bit consentono di manipolare tipi primitivi spostandone i bit verso sinistra o verso destra secondo le regole definite nella tabella seguente byte i = 100; i >> 1; dal momento che la rappresentazione binaria del numero decimale 100 è 01100100, lo shift verso destra di una posizione dei bit, produrrà come risultato il numero binario 00110010 che corrisponde al valore 50 decimale.
  51. 54. Java consente di eseguire operazioni logiche su tipi primitivi operando sulla loro rappresentazione binaria.
  52. 55. <ul><li>Un oggetto non è allocato dal linguaggio al momento della dichiarazione come invece avviene per i tipi primitivi </li></ul><ul><li>Questa dichiarazione crea una variabile intera chiamata counter ed alloca subito quattro byte per lo “storage” del dato. </li></ul><ul><li>int counter; </li></ul><ul><li>Crea una variabile che referenzia l’oggetto, ma non crea l’oggetto Stack. </li></ul><ul><li>Stack s; </li></ul><ul><li>Una variabile di referenza, è quindi una variabile speciale che tiene traccia di istanze di tipi non primitivi </li></ul><ul><li>Una dichiarazione così fatta crea una variabile che tiene traccia di un array di interi di dimensione arbitraria. </li></ul><ul><li> int numbers[]; </li></ul><ul><li>Le variabili reference sono molto simili concettualmente ai puntatori di C e C++ </li></ul>
  53. 56. <ul><li>L’operatore new alloca la memoria necessaria per il nostro oggetto </li></ul><ul><li>Questa locazione può essere memorizzata nella variabile reference ed utilizzata per accedere all’oggetto quando necessario. s = new Stack(); </li></ul><ul><li>Gli array sono allocati allo stesso modo: </li></ul><ul><li>int my_array[] = new int[20]; </li></ul>
  54. 57. <ul><li>Java non consente di definire costanti. </li></ul><ul><li>Per far fronte alla mancanza è possibile utilizzare il modificatore final. </li></ul><ul><li>Una variabile dichiarata final si comporta come una costante </li></ul><ul><ul><li>final int a = 3; </li></ul></ul><ul><li>Le variabili di questo tipo vengono inizializzate solo una volta al momento della dichiarazione. </li></ul><ul><li>Qualsiasi altro tentativo di assegnamento si risolverà in un errore di compilazione. </li></ul>
  55. 58. <ul><li>Array </li></ul><ul><li>Giuseppe Dell’Abate </li></ul>
  56. 59. <ul><li>Molto spesso nei programmi si ha l'esigenza di manipolare un gruppo di variabili dello stesso tipo che contengono valori tra loro correlati. </li></ul><ul><li>Un array è uno strumento concettualmente simile ad una tabella, che accomuna sotto un unico nome un insieme di variabili dello stesso tipo: </li></ul><ul><li>Esempio: </li></ul><ul><li>int[] temp = new int[144]; </li></ul>
  57. 60. <ul><li>Come per le variabili semplici dobbiamo indicare un tipo ed un nome, con la differenza che, dopo aver specificato il tipo, è necessario post porre una coppia di parentesi quadre. </li></ul><ul><li>int[] vettoreDiInteri; </li></ul><ul><li>La variabile 'vettoreDiInteri' appena dichiarata non è un vettore, ma solamente un reference ad un vettore </li></ul>
  58. 61. <ul><li>Per creare un vettore dobbiamo ricorrere alla parola riservata 'new', </li></ul><ul><li>vettoreDiInteri = new int[10]; </li></ul><ul><li>Il valore specificato tra parentesi quadre è la dimensione del vettore </li></ul><ul><li>Un vettore è un oggetto in memoria composto da un certo numero di elementi, </li></ul><ul><li>Ognuno dei quali può contenere un valore </li></ul>
  59. 62. <ul><li>La dereferenziazione è un'operazione in cui creiamo una variabile reference che punta ad un array già esistente </li></ul><ul><ul><li>int[] vettoreDiInteri2; vettoreDiInteri2 = vettoreDiInteri; </li></ul></ul><ul><li>Le modifiche apportate all’oggetto si riflettono anche sull’altro </li></ul><ul><li>Per creare veramente un nuovo array occorre copiare il contenuto in un nuovo array </li></ul>
  60. 63. <ul><li>L'operazione che permette di assegnare un valore ad un elemento del vettore. </li></ul><ul><li>Occorre specificare il nome del vettore seguito dal numero dell'elemento tra parentesi quadre: </li></ul><ul><li>vettoreDiInteri[1] = 10; </li></ul><ul><li>Gli elementi di un array si contano a partire da zero. </li></ul><ul><li>vettoreDiInteri[9] = 27; </li></ul>
  61. 64. <ul><li>Un vettore può essere inizializzato con una serie di valori, in modo simile a come si può fare con le variabili. </li></ul><ul><li>L'istruzione: </li></ul><ul><ul><li>int[] vettore = {10,12,14,16,18}; </li></ul></ul><ul><li>equivale alla sequenza: </li></ul><ul><ul><li>int[] vettore = new int[5]; vettore[0] = 10; vettore[1] = 12; vettore[2] = 14; vettore[3] = 16; vettore[4] = 18; </li></ul></ul>
  62. 65. <ul><li>Il linguaggio Java consente di creare array bi-dimensionali </li></ul><ul><li>Gli array bidimensionali sono concettualmente simili ad una tabella rettangolare, dotata di righe e colonne. </li></ul><ul><li>Esempio: </li></ul><ul><li>int i[][] = new int[10][15]; </li></ul><ul><li>E’ possibile definire vettori con un numero qualunque di dimensioni: </li></ul><ul><ul><li>int v1[][][] = new int[10][15][5]; </li></ul></ul><ul><ul><li>int v2[][][][] = new int[10][15][12][5]; </li></ul></ul><ul><li>Tali strutture, in ogni caso, risultano decisamente poco utilizzate. </li></ul><ul><li>I vettori n-dimensionali vengono implementati in Java come array di array. </li></ul>
  63. 66. <ul><li>E’ possibile la realizzazione di tabelle non rettangolari </li></ul><ul><ul><li>int tabella[][] = new int[5][]; </li></ul></ul><ul><ul><li>tabella[0] = new int[3]; </li></ul></ul><ul><ul><li>tabella[1] = new int[2]; </li></ul></ul><ul><ul><li>tabella[2] = new int[5]; </li></ul></ul><ul><ul><li>tabella[3] = new int[2]; </li></ul></ul><ul><ul><li>tabella[4] = new int[6]; </li></ul></ul>
  64. 67. <ul><li>Un Array multidimensionale può essere inizializzato con una serie di valori, in modo simile a come si può fare con gli Array semplici. </li></ul><ul><li>int[] vettore = { { 10,12,14},{16,18},{20,22,24,26}}; </li></ul>
  65. 68. <ul><li>Costrutti decisionali ed iterativi </li></ul><ul><li>Giuseppe Dell’Abate </li></ul>
  66. 69. <ul><li>Un costrutto decisionale permette al programmatore di vincolare l'esecuzione di un'istruzione (o di un blocco di istruzioni) ad una condizione booleana </li></ul><ul><ul><li>condizione booleana è un'espressione della quale si può dire se sia vera o falsa </li></ul></ul><ul><ul><li>blocco di istruzioni è un insieme di istruzioni racchiuso tra parentesi graffe, che vengono trattate dal compilatore Java come se fossero un'istruzione unica </li></ul></ul>
  67. 70. <ul><li>if-else : verificano diverse espressioni e quando viene incontrata l'espressione che restituisce true viene eseguito un determinato pezzo di codice. </li></ul><ul><li>switch-case : viene esaminata UNA SOLA espressione, però a seconda del suo risultato cambia il pezzo di codice che verrà eseguito. </li></ul>
  68. 71. <ul><li>Il costrutto condizionale più usato in Java è l'if che può essere usato nelle due varianti con o senza else </li></ul><ul><ul><ul><li>if ( condizioneBooleana ) istruzione; </li></ul></ul></ul><ul><li>La variante con l'else ha una forma del tipo </li></ul><ul><ul><li>if ( condizioneBooleana ) istruzione1; else istruzione2; </li></ul></ul>
  69. 72. <ul><li>Se vogliamo che venga eseguita più di una istruzione dobbiamo ricorrere ad un blocco: </li></ul><ul><ul><li>if ( condizioneBooleana ) { istruzione1a; istruzione2a; istruzione3a; } else { istruzione1b; istruzione2b; istruzione3b; } </li></ul></ul>
  70. 73. <ul><li>Il costrutto if può comparire anche all'interno di un altro costrutto if, creando strutture nidificate anche molto complesse: </li></ul><ul><ul><li>if( x >= 0 ) if( x <= 10 ) System.out.println(&quot;x compreso 0 e 10&quot;); </li></ul></ul><ul><li>Se a questo punto inserisco un else dopo queste istruzioni. </li></ul><ul><li>if( x >= 0 ) if( x <= 10 ) System.out.println(&quot;x è compreso tra 0 e 10&quot;); else System.out.println(&quot;x è maggiore di 10&quot;); </li></ul><ul><li>A quale dei due if l’istruzione else farà riferimento? </li></ul>
  71. 74. <ul><li>Se ora aggiungiamo un else a quale if si riferisce? </li></ul><ul><ul><li>if( x >= 0 ) if( x <= 10 ) System.out.println(&quot;x compreso 0 e 10&quot;); else System.out.println(&quot;x maggiore di 10&quot;); else System.out.println(&quot;x minore di 0&quot;); </li></ul></ul><ul><li>Se volessimo forzare un solo else a far riferimento ad un if esterno? </li></ul>
  72. 75. <ul><li>Else esterno: </li></ul><ul><li>if( x >= 0 ) { if( x <= 10 ) System.out.println(&quot;x compreso 0 e 10&quot;); } else System.out.println(&quot;x è minore di 0&quot;); </li></ul><ul><li>abbiamo cosi creato un blocco di istruzioni </li></ul>
  73. 76. <ul><li>E' buona norma di programmazione evitare di ricorrere pesantemente alla nidificazione di istruzioni if, data la confusione che spesso ne segue: </li></ul><ul><ul><li>if( x >= 0 ) if( x <= 10 ) System.out.println(&quot;x compreso 0 e 10&quot;); </li></ul></ul><ul><li>può tranquillamente essere sostituito dal seguente, in tutto equivalente: </li></ul><ul><ul><li>if( x >= 0 && x <= 10 ) System.out.println(&quot;x compreso 0 e 10&quot;); </li></ul></ul>
  74. 77. <ul><li>Una combinazione condizionale si ha quando si fa seguire ad un else una if. </li></ul><ul><ul><li>if( x <= 0 ) System.out.println(&quot;x <= 0&quot;); else if( x <= 10) System.out.println(&quot;x > 0 e <= 10&quot;); else if ( x <= 20) System.out.println(&quot;x > 10 <= 20&quot;); else System.out.println(&quot;x è maggiore di 20&quot;); </li></ul></ul><ul><li>Si noti che in questo caso l'ultimo else comprende tutti i casi non considerati dalle precedenti istruzioni. </li></ul>
  75. 78. <ul><li>L'operatore ? può essere usato all'interno di espressioni matematiche, dove una delle sotto espressioni sia vincolata ad una particolare condizione booleana. </li></ul><ul><ul><li>espressioneBooleana ? espressione1 : espressione2; </li></ul></ul><ul><li>Esempio: </li></ul><ul><ul><li>y = x < 0 ? 1 : 2; </li></ul></ul><ul><ul><li>if (x < 0) y = 1; else y=2; </li></ul></ul>
  76. 79. <ul><li>Il costrutto switch permette di gestire tutte quelle situazioni in cui dobbiamo prendere scelte diverse a seconda del valore di un'espressione </li></ul><ul><li>switch (espressione) { case val1: istruzione_na; break; case val2: istruzione_nb;break; default: istruzione_ndefault;break; } </li></ul>
  77. 80. <ul><li>L'espressione contenuta tra le parentesi dello switch deve essere di tipo intero (int, byte, short o char); </li></ul><ul><li>ogni istruzione case lavora su di un particolare valore, e fornisce una sequenza di istruzioni da eseguire in quella circostanza </li></ul><ul><li>Tale sequenza termina usualmente con l'istruzione break , che forza il computer a uscire dallo switch, senza verificare i valori successivi. </li></ul><ul><li>blocco di default , ovvero una sequenza di istruzioni da eseguire se non si è verificato nessuno dei casi precedenti. </li></ul>
  78. 81. <ul><li>I cicli vengono abitualmente utilizzati in tutti quei casi in cui bisogna eseguire delle attività ripetitive in modo automatica. </li></ul><ul><li>Due tipi di cicli: </li></ul><ul><ul><li>i cicli con contatore o cicli for </li></ul></ul><ul><ul><ul><li>I cicli contatore servono per svolgere una data attività per un numero determinato di volte </li></ul></ul></ul><ul><ul><li>i cicli condizionali o cicli while, do-while </li></ul></ul><ul><ul><ul><li>i cicli condizionali vengono usati per eseguire un'attività fino a quando una data condizione viene soddisfatta </li></ul></ul></ul>
  79. 82. <ul><li>La struttura generale del while è </li></ul><ul><ul><li>while(condizioneBooleana) { ISTRUZIONE1; ISTRUZIONE2; .... } </li></ul></ul>
  80. 83. <ul><li>Se si desidera che un ciclo venga ripetuto all'infinito, è sufficiente specificare una condizione sempre vera, tipo </li></ul><ul><ul><li>while(0 == 0) { ISTRUZIONE1; } </li></ul></ul><ul><li>oppure </li></ul><ul><ul><li>while(true) { ISTRUZIONE1; } </li></ul></ul>
  81. 84. <ul><li>Si desidera che il ciclo venga ripetuto un numero prefissato di volte </li></ul><ul><ul><li>i = 0; while(i<=100) { ISTRUZIONI DA RIPETERE i = i + 1; } </li></ul></ul>
  82. 85. <ul><li>L’istruzione do-while, a differenza della precedente, controlla il valore della espressione booleana alla fine del blocco di istruzioni. In questo caso il blocco di istruzioni verrà eseguito almeno una volta. </li></ul><ul><li>La sintassi di do-while è la seguente </li></ul><ul><ul><li>do { </li></ul></ul><ul><ul><li>istruzione; </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>while (espressione_booleana) { </li></ul></ul><ul><ul><li>istruzione; </li></ul></ul><ul><ul><li>}; </li></ul></ul>
  83. 86. <ul><li>il ciclo di 10 iterazioni utilizzando il ciclo while </li></ul><ul><ul><li>i=0; while(i<10) { faiQualcosa(); i++; } </li></ul></ul><ul><li>comporta maggior elaborazione da parte del programmatore pertanto è possibile usare l’istruzione for </li></ul><ul><ul><li>for(init_statement ; conditional_expr ; iteration_stmt) { istruzione } </li></ul></ul>
  84. 87. <ul><li>init_statement rappresenta l’inizializzazione della variabile per il controllo del ciclo </li></ul><ul><li>conditional_expr l’espressione condizionale </li></ul><ul><li>iteration_stmt l’aggiornamento della variabile di controllo </li></ul><ul><li>Il problema presentato precedentemente può essere risolto utilizzando il ciclo for in questo modo: </li></ul><ul><ul><li>for (int i=0 ; i<10 ; i++) faiQualcosa(); </li></ul></ul>
  85. 88. <ul><li>Il linguaggio Java consente l’uso di tre parole chiave che consentono di modificare in qualunque punto del codice il normale flusso della esecuzione della applicazione con effetto sul blocco di codice in esecuzione o sul metodo corrente. </li></ul>
  86. 89. <ul><li>Questa istruzione consente di forzare l’uscita da un ciclo aggirando il controllo sulla espressione booleana e provocandone l’uscita immediata. </li></ul><ul><ul><li>for (int i=0; ; i++) { if(i==10) break; faiQualcosa(); } </li></ul></ul>
  87. 90. <ul><li>Questa istruzione produce un salto alla parentesi graffa che chiude il blocco </li></ul><ul><ul><li>public void metodo() { </li></ul></ul><ul><ul><li>int i=0; boolean x = false; </li></ul></ul><ul><ul><li>while(i<5) { </li></ul></ul><ul><ul><li>i++; </li></ul></ul><ul><ul><li>if(i== 5) { </li></ul></ul><ul><ul><li>x = true; </li></ul></ul><ul><ul><li>System.out.println(i + &quot; &quot; + x); </li></ul></ul><ul><ul><li>continue; </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul>
  88. 91. <ul><li>Questa istruzione rappresenta l’ultima istruzione di ramificazione e può essere utilizzata per terminare l’esecuzione del metodo corrente tornando il controllo al metodo chiamante. Due forme: </li></ul><ul><ul><li>return valore: viene utilizzata per consentire ad un metodo di ritornare valori al metodo chiamante e pertanto deve ritornare un valore compatibile con quello dichiarato nella definizione del metodo. </li></ul></ul><ul><ul><li>return: può essere utilizzata per interrompere l’esecuzione di un metodo qualora il metodo ritorni un tipo void </li></ul></ul>
  89. 92. <ul><li>Incapsulamento, ereditarietà e polimorfismo </li></ul><ul><li>Giuseppe Dell’Abate </li></ul>
  90. 93. <ul><li>L'incapsulamento è una tecnica mediante la quale si proteggono i dati evitando che si possano manipolare, lasciando però la possibilità di interrogarne il valore. </li></ul><ul><li>In alcuni linguaggi procedurali esiste solo &quot;l'incapsulamento sui tipi primitivi&quot;, ma non quello sui nuovi tipi definiti dall'utente. </li></ul><ul><li>Nei linguaggi OOP, invece, è supportato anche l'incapsulamento per i tipi di dati definiti dall'utente </li></ul><ul><li>In altri termini l'incapsulamento consente di legare, in riferimento alla classe, i dati (membri o variabili) e le operazioni (metodi o funzioni) con una limitazione di accesso ad essi. </li></ul><ul><li>Questo modo di operare protetto elimina i problemi di difficoltà di manutenzione </li></ul>
  91. 94. <ul><li>Esempio: </li></ul><ul><li>class MiaClasse { </li></ul><ul><li>private int x; </li></ul><ul><li>public int leggo() { </li></ul><ul><li>return x; </li></ul><ul><li>} </li></ul><ul><li>public void scrivo(int x) { </li></ul><ul><li>this.x = x; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>In questa classe possiamo notare che la proprietà x privata è accessibile in scrittura dal metodo scrivo() ed in lettura dal metodo leggo() </li></ul>
  92. 95. <ul><li>L'ereditarietà consente di definire un tipo ( classe ) sulla base dei dati e dei metodi di un tipo già definito, ereditandone operativamente sia i dati che i metodi. </li></ul><ul><li>La classe di partenza è la &quot;classe base&quot; o &quot;superclasse&quot; o &quot;classe padre&quot;; mentre la classe che si crea è la &quot;classe derivata&quot; o la &quot;sottoclasse&quot; o la &quot;classe figlia&quot;. </li></ul><ul><li>Nella terminologia OOP si usa anche il termine &quot;estendere&quot; che indica la creazione di una classe derivata da una classe base. </li></ul><ul><li>Non bisogna mai confondere l'ereditarietà con l'incorporamento (classe contenitore)! </li></ul><ul><li>Di grosso aiuto sono, nel linguaggio corrente, i verbi &quot;E' un&quot; e &quot;Ha un&quot;. </li></ul>
  93. 96. <ul><li>Esempio: </li></ul><ul><li>class Padre { </li></ul><ul><li>int x = 5; </li></ul><ul><li>} </li></ul><ul><li>public class Figlio extends Padre { </li></ul><ul><li>public static void main(String[] args) { </li></ul><ul><li>Figlio pr = new Figlio(); </li></ul><ul><li>pr.leggo(); </li></ul><ul><li>} </li></ul><ul><li>void leggo() { </li></ul><ul><li>System.out.println(x); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>La classe Figlio eredita la prorietà x dalla classe Padre e può usarla al suo interno </li></ul>
  94. 97. <ul><li>Derivato dal greco, significa “pluralità di forme” </li></ul><ul><li>E’ la caratteristica che ci consente di utilizzare un’unica interfaccia per una moltitudine di azioni. Quale sia la particolare azione eseguita dipende solamente dalla situazione in cui ci si trova. </li></ul><ul><li>Mentre con gli oggetti il collegamento con la classe avviene a compile-time, nel caso del polimorfismo avviene a run-time </li></ul><ul><li>Il polimorfismo viene impiegato impiegando una interfaccia, una classe astratta o una classe. </li></ul><ul><li>E’ necessario che ci sia ereditarietà tra le classi </li></ul>
  95. 98. <ul><li>Esempio: </li></ul><ul><li>abstract class Figura { </li></ul><ul><li>abstract void rispondo(); </li></ul><ul><li>} </li></ul><ul><li>class Triangolo extends Figura { </li></ul><ul><li>void rispondo(){System.out.println(&quot;Sono il triangolo&quot;);} </li></ul><ul><li>} </li></ul><ul><li>class Rettangolo extends Figura { </li></ul><ul><li>void rispondo(){System.out.println(&quot;Sono il rettangolo&quot;);} </li></ul><ul><li>} </li></ul>Figura Triangolo Rettangolo
  96. 99. <ul><li>Continua… esempio: </li></ul><ul><li>public class Altro { </li></ul><ul><li>Figura pr; </li></ul><ul><li>public static void main(String[] args) { </li></ul><ul><li>Altro al = new Altro(); </li></ul><ul><li>al.metodo(); </li></ul><ul><li>} </li></ul><ul><li>void metodo() { </li></ul><ul><li>pr = new Triangolo(); </li></ul><ul><li>pr.rispondo(); </li></ul><ul><li>pr = new Rettangolo(); </li></ul><ul><li>pr.rispondo(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>Tutto ciò è possibile se esiste ereditarietà!! </li></ul>
  97. 100. <ul><li>Overloading ed overridding </li></ul><ul><li>Giuseppe Dell’Abate </li></ul>
  98. 101. <ul><li>Per riferirsi agli oggetti ed ai metodi si utilizzano dei nomi. </li></ul><ul><li>Nomi scelti con criterio rendono più semplice la comprensione del codice. </li></ul><ul><li>Spesso la stessa parola esprime differenti significati: è overloaded . </li></ul><ul><li>In Java c’è la possibilità di utilizzare lo stesso nome per fare riferimento a più metodi </li></ul><ul><li>Il metodo da eseguire viene stabilito in funzione del contesto </li></ul><ul><li>Il contesto è indicato dagli argomenti e dal valore di ritorno del metodo </li></ul><ul><li>Tipicamente il metodo costruttore di una classe è overloaded, visto che spesso è utile stabilire diversi modi di inizializzazione dell’oggetto </li></ul>
  99. 102. <ul><li>Esempio di overloading del costruttore: </li></ul><ul><li>class Esempio { </li></ul><ul><li>int prop; </li></ul><ul><li>public Esempio() { codice }; </li></ul><ul><li>public Esempio(int prop) { </li></ul><ul><li>this.prop=prop; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>In questo esempio anche prop è overloaded . Con il riferimento this si risolve l’ambiguità. </li></ul>L’argomento identifica univocamente il metodo
  100. 103. <ul><li>Esempio di overloading di un metodo: </li></ul><ul><li>class Esempio { </li></ul><ul><li>int prop; </li></ul><ul><li>public void metodo() { codice }; </li></ul><ul><li>public int metodo() { </li></ul><ul><li>return prop; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>I valori di ritorno identificano univocamente i metodi
  101. 104. <ul><li>Con il termine overriding si intende la ridefinizione di un metodo ereditato. </li></ul><ul><li>Una sottoclasse specializza il comportamento del padre e quindi spesso c’è la necessità di ridefinirne il codice, riscrivendolo o aggiungendo delle funzionalità. </li></ul><ul><li>In alcuni casi è proprio necessario implementare dei metodi (vedi Classi astratte e Interfacce). </li></ul>
  102. 105. <ul><li>Esempio di overriding di un metodo: </li></ul><ul><li>class Padre { </li></ul><ul><li>public void metodo() { codice } </li></ul><ul><li>} </li></ul><ul><li>class Figlio extends Padre { </li></ul><ul><li>public void metodo() { nuovo codice } </li></ul><ul><li>} </li></ul>
  103. 106. <ul><li>Esempio di overriding con riscrittura del codice: </li></ul><ul><li>class Padre { </li></ul><ul><li>int prop; </li></ul><ul><li>public void metodo() { prop=5; } </li></ul><ul><li>} </li></ul><ul><li>class Figlio extends Padre { </li></ul><ul><li>int prop2; </li></ul><ul><li>public void metodo() { prop2=13; prop=14; } </li></ul><ul><li>} </li></ul>
  104. 107. <ul><li>Esempio di overriding con aggiunta di codice: </li></ul><ul><li>class Padre { </li></ul><ul><li>int prop; </li></ul><ul><li>public void metodo() { prop=5; } </li></ul><ul><li>} </li></ul><ul><li>class Figlio extends Padre { </li></ul><ul><li>int prop2; </li></ul><ul><li>public void metodo() { super(); prop2=3; } </li></ul><ul><li>} </li></ul>
  105. 108. <ul><li>Classi annidate </li></ul><ul><li>Giuseppe Dell’Abate </li></ul>
  106. 109. <ul><li>Le classi interne (inner classes) sono l'unica modifica sintattica del linguaggio nel passaggio dalla versione 1.0 a 1.1. </li></ul><ul><ul><li>In Java 1.0 tutte le classi si trovavano allo stesso livello (top level) e non potevano contenere altre classi </li></ul></ul><ul><ul><li>In Java 1.1 , all'interno di una classe possono essere specificate definizioni di altre classi che hanno una stretta relazione funzionale con la classe contenitrice. </li></ul></ul>
  107. 110. <ul><li>A seconda della definizione e dell'ambito in cui viene deinita una classe interna, si possono distinuere quattro casi: </li></ul><ul><ul><li>classi annidate di livello superiore (nested top-level classes); </li></ul></ul><ul><ul><li>classi membro (member classes); </li></ul></ul><ul><ul><li>classi locali (local classes); </li></ul></ul><ul><ul><li>classi anonime (anonymous classes). </li></ul></ul>
  108. 111. <ul><li>Classe interna che è stata definita con il modificatore static </li></ul><ul><li>Possono essere richiamate: </li></ul><ul><ul><li>Nella stessa classe attraverso una istanza della classe e successivamente richiamando il metodo. </li></ul></ul><ul><ul><li>Da un’altra classe attraverso la dichiarazione import oppure indicando la sua classe esterna e poi la classe interna. Viene trattata al pari di un package </li></ul></ul>
  109. 112. <ul><li>Possiamo richiamare la classe annidata statica dall'interno della classe indicando: class Prova { public static void main(String[] args) { ProvaStatica ps = new ProvaStatica(); ps.metodo(); } static class ProvaStatica { void metodo() { System.out.println(&quot;Hello World!&quot;); } }; } </li></ul>
  110. 113. <ul><li>Possiamo richiamare la classe annidata statica dall'esterno della classe non importandola </li></ul><ul><li>class Prova { static class ProvaStatica { void metodo() { System.out.println(&quot;Hello World!&quot;); } }; } </li></ul><ul><li>class ClasseEsterna { public static void main(String[] args) { Prova.ProvaStatica ps = new Prova.ProvaStatica(); ps.metodo(); } } </li></ul>
  111. 114. <ul><li>Possiamo richiamare la classe annidata statica dall'esterno della classe importandola: </li></ul><ul><li>class Prova { static class ProvaStatica { void metodo() { System.out.println(&quot;Hello World!&quot;); } }; } </li></ul><ul><li>import ProvaStatica; </li></ul><ul><li>class ClasseEsterna { public static void main(String[] args) { ProvaStatica ps = newProvaStatica(); ps.metodo(); } } </li></ul>
  112. 115. <ul><li>Le classi membro sono classi elemento che non sono state dichiarate static ed appartengono perciò in tutto e per tutto all'oggetto </li></ul><ul><li>Possono essere richiamate: </li></ul><ul><ul><li>Nella stessa classe attraverso attraverso una istanza della classe e successivamente richiamando il metodo. </li></ul></ul><ul><ul><li>Da un’altra classe attraverso la dichiarazione import oppure indicando la sua classe esterna e poi la classe interna. Viene trattata al pari di un package </li></ul></ul>
  113. 116. <ul><li>class Prova { </li></ul><ul><li>public static void main(String[] args) { </li></ul><ul><li>Prova p = new Prova(); </li></ul><ul><li>ProvaStatica ps = p.new ProvaStatica(); </li></ul><ul><li>ps.metodo(); </li></ul><ul><li>} </li></ul><ul><li>class ProvaStatica { </li></ul><ul><li>void metodo() { </li></ul><ul><li>System.out.println(&quot;Hello World!&quot;); </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul><ul><li>} </li></ul>
  114. 117. <ul><li>class Prova { </li></ul><ul><li>class ProvaStatica { </li></ul><ul><li>void metodo() { </li></ul><ul><li>System.out.println(&quot;Hello World!&quot;); </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul><ul><li>} </li></ul><ul><li>import Prova.ProvaStatica; </li></ul><ul><li>class Avvia { </li></ul><ul><li>public static void main(String[] args) { </li></ul><ul><li>Prova p = new Prova(); </li></ul><ul><li>ProvaStatica ps = p.new ProvaStatica(); </li></ul><ul><li>ps.metodo(); </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul>
  115. 118. <ul><li>class Prova { </li></ul><ul><li>class ProvaStatica { </li></ul><ul><li>void metodo() { </li></ul><ul><li>System.out.println(&quot;Hello World!&quot;); </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul><ul><li>} </li></ul><ul><li>class Avvia { </li></ul><ul><li>public static void main(String[] args) { </li></ul><ul><li>Prova p = new Prova(); </li></ul><ul><li>Prova.ProvaStatica ps = p.new ProvaStatica(); </li></ul><ul><li>ps.metodo(); </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul>
  116. 119. <ul><li>Una classe locale è una classe che è state definita all'interno di un qualunque blocco di codice </li></ul><ul><li>Possono accedere soltanto alle variabili dichiarate come final (per evitare conflitti che potrebbero sorgere tra più classi, definite nello stesso blocco, che dovessero agire sulle stesse variabili ... ) </li></ul>
  117. 120. <ul><li>class Prova { public static void main(String[] args) { Prova p = new Prova(); p.metodo(); } void metodo() { class ProvaStatica { void metodo2() { System.out.println(&quot;Hello World!&quot;); } }; ProvaStatica ps = new ProvaStatica(); ps.metodo2(); } } </li></ul>
  118. 121. <ul><li>Quando di una classe locale che estende qualche altro oggetto viene richiesto che la sua istanza sia unica e non è necessario che venga memorizzata in una variabile, è possibile utilizzare l'abbreviazione delle classi anonime </li></ul><ul><li>new classe_estesa ( lista_argomenti_costruttore ) { blocco } </li></ul><ul><li>L'uso delle classi anonime è consigliato ogniqualvolta le estensioni sono di piccola estensione; altrimenti si consiglia l'uso di classi locali </li></ul>
  119. 122. <ul><li>Esempio di classe anonima locale utilizzando una classe astratta </li></ul><ul><li>public class Parcel7 { public Wrapping wrap() { return new Wrapping() { private int i = 2; public int value() { return i; } }; } public static void main(String[] args) { Parcel7 p = new Parcel7(); Wrapping w = p.wrap(); System.out.println(w.value()); } abstract class Wrapping { public abstract int value(); } } </li></ul>
  120. 123. <ul><li>Esempio di classe anonima locale utilizzando una interfaccia </li></ul><ul><li>public class Parcel7 { public Wrapping wrap() { return new Wrapping() { private int i = 2; public int value() { return i; } }; } public static void main(String[] args) { Parcel7 p = new Parcel7(); Wrapping w = p.wrap(); System.out.println(w.value()); } interface Wrapping { public int value(); } } </li></ul>
  121. 124. <ul><li>Esempio di classe anonima locale utilizzando una classe </li></ul><ul><li>public class Parcel7 { public Wrapping wrap() { return new Wrapping() { private int i = 2; public int value() { return i; } }; } public static void main(String[] args) { Parcel7 p = new Parcel7(); Wrapping w = p.wrap(); System.out.println(w.value()); } class Wrapping { public int value(){ return 0; } } } </li></ul>
  122. 125. <ul><li>Una classe anonima accetta solamente costanti e non variabili, ciò per evitare che vengano a generarsi manipolazioni confusionarie delle variabili nel codice. </li></ul><ul><li>public class Parcel7 { public Wrapping wrap(final int x) { return new Wrapping() { int i = x; public int value() { return i; } }; } public static void main(String[] args) { Parcel7 p = new Parcel7(); Wrapping w = p.wrap(2); System.out.println(w.value()); } interface Wrapping { public int value(); } } </li></ul>
  123. 126. <ul><li>Eccezioni </li></ul><ul><li>Giuseppe Dell’Abate </li></ul>
  124. 127. <ul><li>Una eccezione è un evento che si verifica durante l’esecuzione di un programma e che ne impedisce la normale prosecuzione a causa di errori hardware o semplici errori di programmazione. </li></ul><ul><li>Il sistema runtime, per la gestione dell’eccezione, cerca“candidati” a partire dal metodo nel quale l’eccezione è stata“sollevata”, proseguendo eventualmente lungo lo stack delle chiamate, finché non trova un metodo contenente un gestore(exception handler) opportuno. </li></ul><ul><li>Se non viene trovato nessun exception handler adatto alla gestione di un’eccezione, il programma termina. </li></ul>
  125. 128. <ul><li>Vantaggi rispetto alle tecniche “tradizionali”: </li></ul><ul><ul><li>separazione del codice di gestione degli errori dal normale codice del programma </li></ul></ul><ul><ul><li>propagazione degli errori lungo lo stack delle chiamate dei metodi </li></ul></ul><ul><ul><li>raggruppamento dei vari tipi di errori e loro differenziazione </li></ul></ul>
  126. 129. <ul><li>La classe Throwable ha due discendenti dirette: Error e Exception </li></ul><ul><li>Errori (classe Error): sono generati quando si verificano problemi “seri” nell’esecuzione del programma, dovuti a malfunzionamenti della macchina virtuale Java (piuttosto rari) </li></ul><ul><li>Eccezioni (classe Exception): segnalano che si è verificato un problema nell’esecuzione del programma (il problema, comunque, non è dovuto ad un malfunzionamento del sistema) </li></ul><ul><li>Le eccezioni runtime hanno un “vantaggio”: non devono necessariamente essere specificate nelle intestazioni dei metodi o esplicitamente gestite tramite costrutti try-catch (a differenza, ad esempio, di quelle di input/output) </li></ul>
  127. 131. <ul><li>Una eccezione potrà essere: </li></ul><ul><ul><li>gestita attraverso gli exception handler </li></ul></ul><ul><ul><li>propagata lungo lo stack delle chiamate dei metodi </li></ul></ul>
  128. 132. <ul><li>Un exception handler è composto da tre parti principali: </li></ul><ul><ul><li>un blocco try </li></ul></ul><ul><ul><li>uno o più blocchi catch (opzionali) </li></ul></ul><ul><ul><li>un blocco finally </li></ul></ul>
  129. 133. <ul><li>Racchiude il codice che può sollevare l’eccezione (o le eccezioni) e deve necessariamente essere seguito da un blocco catch o da un blocco finally </li></ul><ul><li>Struttura del costrutto try: </li></ul><ul><ul><li>try { </li></ul></ul><ul><ul><li>....... </li></ul></ul><ul><ul><li>} </li></ul></ul>
  130. 134. <ul><li>racchiudono il codice che gestisce l’eccezione sollevata nel blocco try </li></ul><ul><li>Struttura del costrutto catch: </li></ul><ul><li>catch (<tipo eccezione> <variabile>) { </li></ul><ul><li> gestione dell’eccezione </li></ul><ul><li>} </li></ul><ul><ul><li>< tipo eccezione > deve essere il nome di una classe che eredita dalla classe Throwable </li></ul></ul><ul><ul><li>< variabile > è il nome attraverso cui il gestore dell’eccezione può riferirsi ad essa (identifica cioè un oggetto eccezione) </li></ul></ul>
  131. 135. <ul><li>Viene sempre eseguito al termine dell’esecuzione del contenuto del blocco try (indipendentemente dal fatto che siano state sollevate eccezioni oppure no) </li></ul><ul><li>Consente, ad esempio, di chiudere file aperti nel blocco try (i quali, magari, rimarrebbero aperti in seguito al verificarsi di un errore non esplicitamente gestito in un catch) </li></ul><ul><li>Consente di evitare duplicazione di codice nei blocchi catch </li></ul><ul><li>Struttura del costrutto finally </li></ul><ul><li>finally { </li></ul><ul><li>....... </li></ul><ul><li>} </li></ul>
  132. 136. <ul><li>Struttura generale del costrutto try-catch-finally (con due catch) </li></ul><ul><ul><li>try { </li></ul></ul><ul><ul><li>....... </li></ul></ul><ul><ul><li>} catch (...) { </li></ul></ul><ul><ul><li>....... </li></ul></ul><ul><ul><li>} catch (...) { </li></ul></ul><ul><ul><li>....... </li></ul></ul><ul><ul><li>} finally { </li></ul></ul><ul><ul><li>....... </li></ul></ul><ul><ul><li>} </li></ul></ul>
  133. 137. <ul><li>Nel caso si decida di propagare una eccezione lungo lo stack delle chiamate occorre utilizzare la parola chiave throws al metodo. </li></ul><ul><li>La propagazione dell’eccezione di un metodo indica la volontà di non volersi preoccupare della sua gestione. </li></ul><ul><li>Se i metodi chiamanti non hanno previsto la gestione dell’errore, allora il programma si interromperà. </li></ul><ul><li>public void metodo () throws IOException { </li></ul><ul><li>… ... </li></ul><ul><li>} </li></ul>
  134. 138. <ul><li>E’ possibile lanciare un eccezione nel caso si voglia che venga propagata lungo lo stack delle chiamate dei metodi: </li></ul><ul><ul><li>void metodo() throws IOException { </li></ul></ul><ul><ul><ul><li>if (...) { </li></ul></ul></ul><ul><ul><ul><ul><li>throw new IOException(); </li></ul></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>} </li></ul></ul>
  135. 139. <ul><li>La creazione di eccezioni da parte del programmatore nasce dalla necessità di gestire efficacemente situazioni di errore (o comunque anomale) non previste dalle eccezioni standard di Java ma che si possono comunque verificare durante l’esecuzione del programma che si sta progettando </li></ul><ul><li>Esempio: </li></ul><ul><li>public class ElementoInesistenteException extends Exception { </li></ul><ul><li>public String nomeElemento; </li></ul><ul><li>ElementoInesistenteException(String nome) { </li></ul><ul><li>super(&quot;Non esiste alcun elemento'&quot; + nome); </li></ul><ul><li>nomeElemento = nome; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  136. 140. <ul><li>Stream </li></ul><ul><li>Giuseppe Dell’Abate </li></ul>
  137. 141. <ul><li>Il package java.io è composto da due parti principali: </li></ul><ul><ul><li>stream di byte : utilizzati per gestire un flusso di byte (8 bit) </li></ul></ul><ul><ul><li>stream di caratteri : impiegati per maneggiare un flusi di caratteri UNICODE(16 bit) </li></ul></ul><ul><li>Per ogni stream esistono i corrispondenti stream di input e di output </li></ul><ul><ul><li>stream di byte : InputStream ed OutputStream </li></ul></ul><ul><ul><li>stream di caratteri : Reader e Writer </li></ul></ul><ul><li>Quando si parla semplicemente di stream si intende uno stream di qualunque tipo (di byte o di caratteri , di input o di output) </li></ul>
  138. 142. <ul><li>InputStream : ci permette di gestire in input i files in blocchi da 8 bit=1 byte. </li></ul>
  139. 143. <ul><li>Esempio di una classe che legge i byte di un file passato come parametro </li></ul><ul><li>import java.io.*; </li></ul><ul><li>class ProvaInputStream { </li></ul><ul><li>public static void main(String[] args) throws IOException { </li></ul><ul><li>InputStream is = new FileInputStream(args[0]); </li></ul><ul><li>int b; </li></ul><ul><li>while ( (b = is.read()) != -1 ) </li></ul><ul><li>System.out.println(&quot;Letto : &quot; + (char)b); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  140. 144. <ul><li>OutputStream : ci permette di gestire in output i files in blocchi da 8 bit=1 byte. </li></ul>
  141. 145. <ul><li>Esempio di una classe che scrive dei dati in un file </li></ul><ul><li>import java.io.*; </li></ul><ul><li>class ProvaOutputStream { </li></ul><ul><li>public static void main(String[] args) throws IOException { </li></ul><ul><li>OutputStream os = new FileOutputStream(args[0]); </li></ul><ul><li>int b; </li></ul><ul><li>while ( (b = System.in.read()) != -1 ) </li></ul><ul><li>os.write(b); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  142. 146. <ul><li>Reader : ci permette di gestire in input i flussi di caratteri in blocchi da 16 bit=2 byte. </li></ul>
  143. 147. <ul><li>Esempio di una classe che scrive dei dati in un file </li></ul><ul><li>import java.io.*; </li></ul><ul><li>class ProvaReader { </li></ul><ul><li>public static void main(String[] args) throws IOException { </li></ul><ul><li>Reader r = new FileReader(args[0]); </li></ul><ul><li>int c; </li></ul><ul><li>while ( (c = r.read()) != -1 ) </li></ul><ul><li>System.out.println(“Leggo:” + (char)c); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  144. 148. <ul><li>Writer : ci permette di gestire in output i files in blocchi da 16 bit=2 byte. </li></ul>
  145. 149. <ul><li>Esempio di una classe che scrive dei dati in un file </li></ul><ul><li>import java.io.*; </li></ul><ul><li>class ProvaWriter { </li></ul><ul><li>public static void main(String[] args) throws IOException { </li></ul><ul><li>Reader r = new InputStreamReader(System.in); </li></ul><ul><li>Writer os = new FileWriter(args[0]); </li></ul><ul><li>int b; </li></ul><ul><li>while ( (b = r.read()) != -1 ) { </li></ul><ul><li>os.write(b); </li></ul><ul><li>os.flush(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  146. 150. <ul><li>E’ possibile creare un buffer di dati in Input - Output per velocizzare la lettura/scrittura dei bytes </li></ul><ul><li>Input Byte </li></ul><ul><li>InputStream is = new FileInputStream(args[0]); </li></ul><ul><li>BufferedInputStream bis = new BufferedInputStream(is); </li></ul><ul><li>Output Byte </li></ul><ul><li>OutputStream is = new FileOutput Stream(args[0]); </li></ul><ul><li>BufferedOutputStream bis = new BufferedOutputStream(is); </li></ul>
  147. 151. <ul><li>E’ possibile creare un buffer di dati in Input - Output anche per la lettura/scrittura dei caratteri, ed usare il metodo readLine() per leggere una riga completa e non un singolo carattere </li></ul><ul><li>Input Carattere </li></ul><ul><li>Reader is = new FileReader(args[0]); </li></ul><ul><li>BufferedReader br = new BufferedReader(is); </li></ul><ul><li>Output Carattere </li></ul><ul><li>Writer w = new FileWriter(args[0]); </li></ul><ul><li>BufferedWriter bw = new BufferedWriter(w); </li></ul>
  148. 152. <ul><li>In Input/Output possono essere impiegati array di </li></ul><ul><ul><li>byte: </li></ul></ul><ul><ul><ul><li>ByteArrayInputStream() </li></ul></ul></ul><ul><ul><ul><li>ByteArrayOutputStream() </li></ul></ul></ul><ul><ul><li>caratteri </li></ul></ul><ul><ul><ul><li>CharArrayReader() </li></ul></ul></ul><ul><ul><ul><li>CharArrayWriter() </li></ul></ul></ul><ul><li>In Input/Output possono essere impiegati stringhe di caratteri </li></ul><ul><ul><li>StringReader() </li></ul></ul><ul><ul><li>StringWriter() </li></ul></ul>
  149. 153. <ul><li>Threads </li></ul><ul><li>Giuseppe Dell’Abate </li></ul>
  150. 154. <ul><li>Java consente di realizzare la concorrenza attraverso i thread </li></ul><ul><li>I threads sono dei programmi &quot;figli&quot; di quello principale. </li></ul><ul><li>Lo scheduling si occupa dell’ordine di esecuzione ed il sistema attiverà quello a priorità maggiore </li></ul><ul><li>L’algoritmo di scheduling del sistema runtime di Java è di tipo preemptive (promozione) </li></ul><ul><li>Il sistema runtime di Java non supporta di per sé il time-slicing. Per evitare che un programma sia dipendente dalla particolare piattaforma fisica (hardware + sistema operativo), è bene non fare affidamento su questa caratteristica </li></ul>
  151. 155. <ul><li>La nostra classe deve essere una sottoclasse della classe astratta java.lang.Thread oppure deve implementare l’interfaccia Runnable, presenti nella libreria del JDK </li></ul><ul><li>Richiamiamo i metodi costruttori; </li></ul><ul><ul><li>public Thread(); </li></ul></ul><ul><ul><li>public Thread(String nome); </li></ul></ul><ul><li>l’esecuzione è avviata con il metodo start() </li></ul><ul><li>il metodo run() contiene le operazioni da effettuare </li></ul><ul><ul><li>public void run() { azioni da svolgere } </li></ul></ul>
  152. 156. <ul><li>class Principale extends Thread { int FineConteggio; public static void main(String argv[]) { Principale Mario=new Principale (&quot;Mario&quot;,100); Principale Anna=new Principale (&quot;Anna&quot;,50); Mario.start(); Anna.start(); } Principale (String Nome, int n) { super(Nome); FineConteggio=n; } public void run() { System.out.println(this.getName()+&quot;: sto contando...&quot;); for (int i=0; i<=FineConteggio; i++) System.out.println(this.getName()+&quot;: &quot;+i); System.out.println(this.getName()+&quot;: ho finito di contare!&quot;); } } </li></ul>
  153. 157. born ready running blocked dead sleeping waiting start notify o notifyall wait sleep comple-tamento invio I/O completamento I/O assegna un processore quantum expiration yield interrupt intervallo di sleep scade
  154. 158. <ul><li>Ad ogni processo è assegnata una priorità ovvero un valore intero positivo che varia tra due valori static della classe Thread: MIN_PRIORITY e MAX_PRIORITY. </li></ul><ul><li>Quando un thread viene creato, come nell'esempio precedente, la sua priorità è pari a NORM_PRIORITY </li></ul><ul><li>Se in un determinato istante esiste un thread nello stato Runnable che ha priorità maggiore di quello corrente, esso viene promosso (pre-empted) sostituendo il precedente che, pur rimanendo nello stato di Runnable, non avanzerà nella esecuzione </li></ul>
  155. 159. <ul><li>Esempio di Thread con diversa priorità che vengono gestiti dallo scheduler secondo il pre-emptive </li></ul><ul><li>public class MioThread extends Thread { public MioThread(String nome_thread){ super(nome_thread); } public void run(){ for (int i=0; i<10;i++) System.out.println(getName()); } </li></ul>
  156. 160. <ul><li>public static void main(String[] str){ MioThread thread1 = new MioThread(&quot;Thread1&quot;); thread1.start(); MioThread thread2 = new MioThread(&quot;Thread2&quot;); thread2.setPriority(Thread.MAX_PRIORITY); thread2.start() ; MioThread thread3 = new MioThread(&quot;Thread3&quot;); thread3.setPriority(Thread.MIN_PRIORITY); thread3.start(); } } </li></ul>
  157. 161. <ul><li>Nel caso di processi di uguale priorità entrano in gioco le caratteristiche proprie di ciascun sistema operativo. </li></ul><ul><li>In molti sistemi operativi UNIX il Thread viene eseguito fino al suo compimento </li></ul><ul><li>Nelle implementazioni della JVM in Window95 o NT ad ogni thread è assegnato un tempo massimo di utilizzo della CPU(quantum) oltre il quale dovrà lasciare la CPU stessa ad altri thread. </li></ul><ul><li>Per gestire le differenze è possibile usare il metodo yield() che sospende l’esecuzione del thread per passarla al prossimo </li></ul>
  158. 162. <ul><li>public class MioThreadWIN extends Thread { </li></ul><ul><li>public MioThreadWIN(String nome_thread){ </li></ul><ul><li>super(nome_thread); </li></ul><ul><li>} </li></ul><ul><li>public void run(){ </li></ul><ul><li>for (int i=0; i<1000000;i++) </li></ul><ul><li>System.out.println(getName()); </li></ul><ul><li>} </li></ul><ul><li>public static void main(String[] str){ </li></ul><ul><li>MioThreadWIN thread1 = new MioThreadWIN(&quot;Thread1&quot;); </li></ul><ul><li>thread1.start(); </li></ul><ul><li>MioThreadWIN thread2 = new MioThreadWIN(&quot;Thread2&quot;); </li></ul><ul><li>thread2.start(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  159. 163. <ul><li>E’ necessario disciplinarne l'accesso su un dato condiviso </li></ul><ul><li>In Java questo si ottiene dichiarando il metodo synchronized </li></ul><ul><li>Se in un certo istante il thread T1 è all'interno di una regione critica su un dato condiviso, allora ogni altro thread che tenti di accedere ad una qualsiasi altra regione critica sullo stesso dato dovrà attendere il suo turno </li></ul>
  160. 164. <ul><li>public synchronized void put(int value) { while (available) { try { wait(); } catch (InterruptedException e) { } } contents = value; available = true; notifyAll(); } </li></ul><ul><li>public synchronized void put2(int value) { while (!available) { try { wait(); } catch (InterruptedException e) { } } contents = value; available = false; notifyAll(); } </li></ul>
  161. 165. <ul><li>Serializzazione </li></ul><ul><li>Giuseppe Dell’Abate </li></ul>
  162. 166. <ul><li>E’ una tecnica che consente di poter salvare un oggetto, o meglio renderlo persistente, e poi ripristinato </li></ul><ul><li>Vi è la possibilità di definire alcune proprietà come transient per cui ne viene salvata l’istanza ma in fase di ripristino i suoi campi assumono i loro valori di default </li></ul><ul><li>Occorre implementare l’interfaccia java.io.Serializable ed occorre che tutti le proprieta siano serializzabili </li></ul><ul><li>Per verificare si puo usare il serialver -show. Apparirà una finestra nella quale metterete il nome completo della classe che volete esaminare. Se la classe è serializzabile apparirà un valore identificativo della classe stessa, altrimenti non apparirà nulla. </li></ul>
  163. 167. <ul><li>public void scrivi () { try{ fos = new FileOutputStream (&quot;restore.ser&quot;); oos = new ObjectOutputStream(fos); oos.writeObject(salvato); oos.close(); } catch (Ioexception ioe){ System.out.println(&quot;Errore:&quot;+ioe.toString()); }// fine catch }// fine metodo scrivi </li></ul>
  164. 168. <ul><li>public void leggi() { try{ fis = new FileInputStream (&quot;restore.ser&quot;); ois = new ObjectInputStream(fis); salvato = (TipoSalvato)(ois.readObject()); ois.close(); } catch (Ioexception ioe){ System.out.println(&quot;Errore:&quot;+ioe.toString()); }// fine catch }// fine metodo leggi </li></ul><ul><li>Operazione di cast da fare all’atto del readObject . Infatti essa ritorna un Object per cui tale operazione si rende necessaria </li></ul>
  165. 169. <ul><li>Oggetti non serializzabili: </li></ul><ul><ul><li>Thread, ResultSet e risorse native </li></ul></ul><ul><li>Oggetti serializzabili </li></ul><ul><ul><li>classi che implementano interfaccia Serializable/Externalizable direttamente o indirettamente </li></ul></ul><ul><ul><li>tipi primitivi </li></ul></ul><ul><ul><li>quasi tutte le AWT </li></ul></ul><ul><li>Posso serializzare soltanto qualche proprietà della classe ? </li></ul>
  166. 170. <ul><li>Risposta : Se voglio rendere una classe serializzabile ANCHE se contiene attributi NON serializzabili… posso farlo, basta indicare quei campi come &quot;ignorabili&quot; dal meccanismo di serializzazione. A tali campi basta aggiungere il modificatore transient . </li></ul><ul><ul><li>public class DaTrasmettere implements Serializable{ int count; // serializzabile String messaggio; // serializzabile transient Thread t; // NON serializzabile !!! } </li></ul></ul><ul><li>Tutti i campi transient vengono saltati durante la serializzazione, per cui bisogna re-inizializzarli all’arrivo </li></ul>
  167. 171. <ul><li>Serializable , quando viene trasmesso l'ObjectStream lo converte in uno stream di byte usando il protocollo predefinito </li></ul><ul><li>Externalizable serve se NON voglio usare il meccanismo standard e voglio leggere e scrivere il MIO oggetto alla MIA maniera </li></ul>
  168. 172. <ul><li>I Socket </li></ul><ul><li>Giuseppe Dell’Abate </li></ul>
  169. 173. <ul><li>Un socket è un flusso di byte che può essere trasmesso tra due host diversi collegati in rete </li></ul><ul><li>Esistono due tipi di socket: </li></ul><ul><ul><li>TCP (Transport Control Protocol) </li></ul></ul><ul><ul><li>UDP (User Datagram Protocol) </li></ul></ul>
  170. 174. <ul><li>Meccanismo “affidabile” ed “orientato alla connessione” </li></ul><ul><ul><li>Affidabile: eventuali errori di comunicazione vengono gestiti dal sistema di trasmissione, pertanto vengono: </li></ul></ul><ul><ul><ul><li>recuperati </li></ul></ul></ul><ul><ul><ul><li>segnalati al programma applicativo </li></ul></ul></ul><ul><ul><li>orientato alla connessione </li></ul></ul><ul><ul><ul><li>tutti i byte vengono ricevuti esattamente come sono stati trasmessi </li></ul></ul></ul><ul><li>Vengono impiegati per FTP ed HTTP </li></ul>
  171. 175. <ul><ul><li>Detti “senza connessione” dal momento che ogni pacchetto di fatto vive indipendentemente dagli altri </li></ul></ul><ul><ul><li>il sistema operativo non garantisce che: </li></ul></ul><ul><ul><ul><li>il pacchetto venga consegnato al destinatario </li></ul></ul></ul><ul><ul><ul><li>la segnalazione di eventuali errori </li></ul></ul></ul><ul><ul><ul><li>che arrivino nello stesso ordine in cui sono spediti </li></ul></ul></ul><ul><ul><ul><li>possono arrivare addirittura in copie multiple </li></ul></ul></ul><ul><ul><li>Per superare questi problemi vengono realizzati dei controlli a livello di applicazione </li></ul></ul><ul><ul><li>Vengono usati per broadcasting e multicasting (NFS,DNS) </li></ul></ul>
  172. 176. <ul><li>Le socket consentono il collegamento tra due host </li></ul><ul><li>Per gestire piu socket si fa uso delle porte </li></ul><ul><li>Porte standard </li></ul><ul><ul><ul><li>FTP 20 - 21 </li></ul></ul></ul><ul><ul><ul><li>Telnet 23 </li></ul></ul></ul><ul><ul><ul><li>SMTP 25 </li></ul></ul></ul><ul><ul><ul><li>POP3 110 </li></ul></ul></ul><ul><ul><ul><li>HTTP 80 </li></ul></ul></ul>
  173. 177. <ul><li>I socket in Java sono implementati con quattro classi distinte: </li></ul><ul><ul><li>1. Socket : socket TCP lato client 2. ServerSocket : socket TCP lato server 3. DatagramSocket : socket UDP semplici e broadcast 4. MulticastSocket : socket UDP multicast </li></ul></ul>
  174. 178. <ul><li>Un socket di tipo TCP deve essere in generale costruito con almeno tre parametri: </li></ul><ul><ul><li>la porta locale (indicata dinamicamente) </li></ul></ul><ul><ul><li>l’indirizzo remoto </li></ul></ul><ul><ul><li>la porta remota </li></ul></ul>
  175. 179. <ul><li>Specifica indirizzo e porta remota; </li></ul><ul><ul><li>public Socket (String addr, int port); </li></ul></ul><ul><li>Manipolare la porta remota di connessione </li></ul><ul><ul><li>public void setPort (int port); </li></ul></ul><ul><ul><li>public int getPort(); </li></ul></ul>
  176. 180. <ul><li>Le socket permette di associarvi una coppia di stream di I/O </li></ul><ul><ul><li>public InputStream getInputStream(); </li></ul></ul><ul><ul><li>public OutputStream getOutputStream(); </li></ul></ul><ul><li>Successivamente possiamo associarvi stream di tipo DataInput e DataOutput e gestire lo stream </li></ul><ul><li>Quando il socket non serve più deve essere chiuso </li></ul><ul><ul><li>public void close(); </li></ul></ul>
  177. 181. <ul><li>public void start()throws Exception { </li></ul><ul><li>DataInputStream stdIn = new DataInputStream(System.in); </li></ul><ul><li>Socket socket = new Socket(”10.30.1.135&quot;, 7777); </li></ul><ul><li>DataOutputStream os = new DataOutputStream(socket.getOutputStream()); </li></ul><ul><li>DataInputStream is = new DataInputStream(socket.getInputStream()); </li></ul><ul><li>for (;;) { </li></ul><ul><li>System.out.print(&quot;input: &quot;); </li></ul><ul><li>String userInput = stdIn.readLine(); </li></ul><ul><li>if (userInput.equals(&quot;QUIT&quot;)) </li></ul><ul><li>break; </li></ul><ul><li>os.writeBytes(userInput + ' '); </li></ul><ul><li>System.out.println(&quot;echo: &quot; + is.readLine()); </li></ul><ul><li>} </li></ul><ul><li>os.close(); is.close(); </li></ul><ul><li>socket.close(); </li></ul><ul><li>} </li></ul>
  178. 182. <ul><li>public void start() throws Exception { </li></ul><ul><li>ServerSocket serverSocket = new ServerSocket(7777); </li></ul><ul><li>for (;;) { </li></ul><ul><li>System.out.println(&quot;Waiting... &quot;); </li></ul><ul><li>Socket socket = serverSocket.accept(); </li></ul><ul><li>System.out.println(&quot;New socket &quot; + socket); </li></ul><ul><li>DataInputStream is = new DataInputStream(socket.getInputStream()); </li></ul><ul><li>DataOutputStream os = new DataOutputStream(socket.getOutputStream()); </li></ul><ul><li>for (;;) { </li></ul><ul><li>String userInput = is.readLine(); os.writeBytes(userInput + ' '); </li></ul><ul><li>System.out.println(&quot;Replying &quot; + userInput); </li></ul><ul><li>} </li></ul><ul><li>os.close(); is.close(); System.out.println(&quot;Closed socket &quot; + socket); </li></ul><ul><li>socket.close(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  179. 183. <ul><li>Un socket UDP serve per la trasmissione di “piccoli” pacchetti di dati detti datagrammi (secondo lo standard TCP/IP non più lunghi di 1500 byte). </li></ul><ul><li>Java definisce una classe apposita, DatagramPacket, per la loro implementazione </li></ul><ul><ul><li>DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) </li></ul></ul><ul><li>Per gestire i datagrammi esiste la classe DatagramSocket. Per crearne un’istanza è sufficiente specificare il numero della porta: </li></ul><ul><ul><li>public DatagramSocket (int port); </li></ul></ul><ul><li>I datagrammi possono poi essere spediti e ricevuti con i metodi </li></ul><ul><ul><li>send() </li></ul></ul><ul><ul><li>receive() </li></ul></ul>
  180. 184. <ul><li>Manipolano l’indirizzo remoto public int getPort(); </li></ul><ul><ul><li>public InetAddress getAddress(); </li></ul></ul><ul><ul><li>public void setAddress (InetAddress address); </li></ul></ul><ul><li>Manipolano la porta remota </li></ul><ul><ul><li>public void setPort (int port); </li></ul></ul><ul><ul><li>public int getPort(); </li></ul></ul><ul><li>Manipolano il buffer che contiene i dati </li></ul><ul><ul><li>public byte[] getData(); </li></ul></ul><ul><ul><li>public void setData (byte[] data); </li></ul></ul><ul><ul><li>public int getLenght(); </li></ul></ul><ul><ul><li>public void setLenght (int lenght); </li></ul></ul>
  181. 185. <ul><li>import java.net.*; </li></ul><ul><li>public class UDPExample { public static void main (String[] args) throws Exception { byte[] msg = {'H', 'e', 'l', 'l', 'o'}; InetAddress addr = InetAddress.getByName(&quot;192.5.6.7&quot;); DatagramSocket s = new DatagramSocket(2222); DatagramPacket hi = new DatagramPacket(msg, msg.length, addr, 2223); s.send(hi); </li></ul><ul><li>byte[] buf = new byte[1000]; DatagramPacket recv = new DatagramPacket(buf, buf.length); s.receive(recv); } </li></ul><ul><li>} </li></ul>
  182. 186. <ul><li>Per quanto riguarda i socket multicast, essi hanno una classe apposita, MultiCastSocket, che si gestisce analogamente ad un DatagramSocket </li></ul><ul><ul><li>MulticastSocket(int port) </li></ul></ul><ul><li>I metodi joinGroup() e leaveGroup() servono, rispettivamente, per “entrare” ed “uscire” dal gruppo di host. </li></ul>
  183. 187. <ul><li>import java.net.*; </li></ul><ul><li>public class UDPExample { public static void main (String[] args) throws Exception { </li></ul><ul><li>byte[] msg = {'H', 'e', 'l', 'l', 'o'}; </li></ul><ul><li>InetAddress group = InetAddress.getByName(&quot;228.5.6.7&quot;); </li></ul><ul><li>InetAddress addr = InetAddress.getByName(&quot;192.5.6.7&quot;); </li></ul><ul><li>MulticastSocket s = new MulticastSocket(2222); </li></ul><ul><li>s.joinGroup(group); </li></ul><ul><li>DatagramPacket hi = new DatagramPacket(msg, msg.length, addr, 2223); </li></ul><ul><li>s.send(hi); </li></ul><ul><li>byte[] buf = new byte[1000]; </li></ul><ul><li>DatagramPacket recv = new DatagramPacket(buf, buf.length); </li></ul><ul><li>s.receive(recv); </li></ul><ul><li>s.leaveGroup(group); </li></ul><ul><li>}} </li></ul>
  184. 188. <ul><li>Remote Method Interface </li></ul><ul><li>Giuseppe Dell’Abate </li></ul>
  185. 189. <ul><li>Per creare delle applicazioni distribuite, prima veniva usato il Remote Procedure Call (RPC) legato al concetto di processo e di procedura e non al paradigma ad oggetti. </li></ul><ul><li>Fu introdotto l’RMI: un' insieme di API potente ma semplice che permette di sviluppare applicazioni distribuite in rete </li></ul><ul><li>Permette di implementare la: </li></ul><ul><ul><li>Serializzazione </li></ul></ul><ul><ul><li>Socket </li></ul></ul>
  186. 191. <ul><li>Livello di applicazione </li></ul><ul><ul><li>RMI Client : applicazione che effettua le chiamate ai metodi di oggetti remoti risiedenti sul lato server </li></ul></ul><ul><ul><li>RMI Server : applicazione che gestisce gli oggetti serventi </li></ul></ul><ul><li>Remote Reference Layer </li></ul><ul><ul><li>Stub : fornisce una simulazione locale sulla JVM del client dell’oggetto remoto </li></ul></ul><ul><ul><li>Skeleton : è l’oggetto remoto in esecuzione sulla JVM del server </li></ul></ul><ul><li>Transport Layer </li></ul><ul><ul><li>si instaura un collegamento fisico per la trasmissione di sequenza di byte (oggetti serializzati ) attraverso i socket su protocllo TCP/IP </li></ul></ul>
  187. 192. <ul><li>La classe Naming è un registro che mappa dei nomi logici con i references dell'interfacce degli oggetti remoti. </li></ul><ul><li>Ogni associazione nome logico – oggetto remoto è memorizzata in un apposito registro gestito dall'applicazione rmiregistry </li></ul>
  188. 193. <ul><li>import java.rmi.server.*; </li></ul><ul><li>import java.rmi.*; </li></ul><ul><li>import MyServerImpl; </li></ul><ul><li>public class RmiClient { </li></ul><ul><li>public static void main(String[] args) { </li></ul><ul><li>String urlRmiHost = &quot;rmi://10.30.1.135:1099/MyService&quot;; </li></ul><ul><li>try { </li></ul><ul><li>MyServerInterface serverRef = (MyServerInterface)Naming.lookup(urlRmiHost); </li></ul><ul><li>System.out.println(serverRef.concat(&quot;World&quot;)); </li></ul><ul><li>} </li></ul><ul><li>catch (Exception e){} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  189. 194. <ul><li>import java.rmi.server.*; </li></ul><ul><li>import java.rmi.*; </li></ul><ul><li>public interface MyServerInterface extends Remote { </li></ul><ul><li>public String concat(String nome) throws RemoteException; </li></ul><ul><li>} </li></ul>
  190. 195. <ul><li>import java.rmi.server.*; </li></ul><ul><li>import java.rmi.*; </li></ul><ul><li>public class RmiServer { </li></ul><ul><li>public static void main(String [] args) throws Exception{ </li></ul><ul><li>MyServerImpl server = new MyServerImpl(); </li></ul><ul><li>Naming.bind(&quot;MyService&quot;, server); </li></ul><ul><li>System.out.println(&quot;RmiServer : bind done ...&quot;); </li></ul><ul><li>System.out.println(&quot;MyService is now available ...&quot;); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  191. 196. <ul><li>import java.rmi.server.*; </li></ul><ul><li>import java.rmi.*; </li></ul><ul><li>public class MyServerImpl extends UnicastRemoteObject implements MyServerInterface { </li></ul><ul><li>public MyServerImpl() throws RemoteException { } </li></ul><ul><li>public String concat(String nome) throws RemoteException { </li></ul><ul><li>return &quot;Hello &quot; + nome; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>

×