320 likes | 503 Views
CAPITOLO 4. LINGUAGGIO JAVA: COSTRUTTI DI BASE. ALFABETO. Java adotta la codifica standard Unicode della società Unicode, Inc. ( ftp://ftp.unicode.org ) definito in: The Unicode Standard, Worldwide Character Encoding , Version 2.0
E N D
CAPITOLO 4 LINGUAGGIO JAVA: COSTRUTTI DI BASE
ALFABETO • Java adotta la codifica standard Unicode della società Unicode, Inc. (ftp://ftp.unicode.org) definito in: The Unicode Standard, Worldwide Character Encoding, Version 2.0 • I programmi Java possono essere scritti con altre codifiche (e.g. la codifica ASCII a 7 o 8 bit), ma devono essere convertiti alla codifica Unicode (a 16 bit) prima di essere utilizzati da parte di compilatori, interpreti, debugger, etc. • N.B. - Nello standard Unicode, un segmento della codifica è riservato ai caratteri speciali
CODICE SORGENTE • Consiste di una o più unità di compilazione • Ogni unità può contenere (oltre ai commenti) • al più una istruzione package • una o più istruzioni import • una o più dichiarazioni di classe (class) • una o più dichiarazioni di interfaccia (interface) • Per ciascuna unità di compilazione, al più una classe può essere dichiarata public • Il codice sorgente viene compilato a bytecode (cfr. The Java Virtual Machine Specification), un insieme di istruzioni machine-independent
COMMENTI • Presenti in tre diversi stili, non hanno alcuna influenza sulla semantica dei programmi • // Primo stile: io sono un commento su di una sola linea • /* Secondo stile: anch'io sono un commento monolinea */ • /* Secondo stile: io, invece, sono un commento più lungo: non ci sto in una sola linea e quindi ne occupo ben due */ • /** Terzo stile: io sono un commento di tipo speciale, che chiamano "commento di documentazione". */ • Un commento del terzo tipo va collocato solo immediatamente prima di una dichiarazione (di classe, di interfaccia, di costruttore o di membro); viene incluso nella documentazione generabile automaticamente (ex sorgente)
TIPI SEMPLICI "Non tutti i dati sono oggetti" (impurità di Java) • boolean - tipo enumerativo (due elementi) • char - carattere di 16 bit (Unicode 1.1.5) • byte - intero di 8 bit (complemento a 2) • short - intero di 16 bit (complemento a 2) • int - intero di 32 bit (complemento a 2) • long - intero di 64 bit (complemento a 2) • float - floating-point di 32 bit (IEEE 754) • double - floating-point di 64 bit (IEEE 754) Tutti i tipi semplici (o di base) sono predefiniti
TIPI COMPOSTI • Equivalenti alle variabili strutturate PASCAL, nella loro versione dinamica (operatore new) • I dati composti sono mediati, i.e. manipolati per mezzo di puntatori non visibili all'utente (i dati semplici sono immediati, i.e. manipolati direttamente) • Tre categorie di tipi composti • Matrici - versione dinamica degli array PASCAL • Classi - versione "attiva" dei record PASCAL • Interfacce - simili alle dichiarazioni forward in PASCAL • Di questi, solo i tipi matrice sono predefiniti: le librerie di classi e di interfacce non lo sono
LETTERALI (1) • Rappresentazione "esterna" di dati e oggetti • Alcuni tipi semplici ammettono letterali • boolean -true, false • char - 'a', '\u03ff', '\037', '\x7f' - '\', '\n', '\t', '\b', '\r', '\f', '\\', '\'', '\"' • int-127, 0177, 0x7F, 0X7F, 0x7f, 0X7f • long - 127L, 127l, 2147483648 • float-3.14, 3.1E12, 3.1e-12, .1e12, 2e-12 • double-3.14D, 3.14d, 3.1e-12D, .1e12d, 2e-12D • Uno solo dei tipi composti ammette letterali • String- "", "Da\ncapo", "Io non sono Luigi Stringa" • Per gli altri esiste il letterale generico null
LETTERALI (2) • Letterali distinti possono rappresentare lo stesso valore • int-127, 0177, 0x7F • I numeri negativi, di qualunque tipo siano (salvo gli esponenti), non sono esprimibili mediante letterali • Le routine di stampa sono in grado di stampare qualunque dato di tipo semplice • Il formato di stampa è coerente con quello dei letterali (se esiste); nel caso di più formati possibili, ne viene scelto uno come standard
PAROLE CHIAVE (RISERVATE) • Parole chiave: abstract, boolean, break, byte, case, catch, char, class, const (*), continue, default, do, double, else, extends, final, finally, float, for, goto (*), if, implements, import, instanceof, int, interface, long, native, new, package, private, protected, public, return, short, static, super, switch, synchronized, this, throw, transient (*), try, void, volatile, while (*) Inutilizzata nella specifica attuale di Java
IDENTIFICATORI • Debbono iniziare con una lettera (v. sotto) o con uno dei due simboli '_' e '$', e possono contenere qualunque carattere non speciale della codifica Unicode; non hanno (in pratica) limiti di lunghezza • Ai fini di Java, sono lettere • tutti i caratteri compresi tra 'A' e 'Z' e tra 'a' e 'z' • le non-cifre di codice Unicode superiore a 00C0 (hex) • Esempi: identifier, user_name, User_name, _user_name, $user_name, user$name1 • Se attributi di classi, sono inizializzati a false (i boolean), 0 (i tipi numerici) o null (il resto)
MATRICI • Vettori monodimensionali di dati, semplici o composti, di tipo omogeneo • Semplici - char a[]; char[] b; char array[]; • Composti (oggetti) - String args[]; String[] other_args; • Composti (matrici) - char chess[][]; char[][] checkers; Voxel human_body[][][]; • Indicizzati con int (indice primo elemento = 0), con controllo di validità degli indici a run-time • Vanno create e dimensionate esplicitamente, anche contestualmente alla dichiarazione (la quale di per sé non alloca nulla, ma si limita a definire il tipo di un nome, inizializzato a null)
MATRICI: CREAZIONE INIZIALIZZAZIONE • Dichiarazione e successiva creazione int array[][]; /* qui array == null */ array = new int[10][3]; • Dichiarazione e contestuale creazione int array[][] = new int[10][3]; • Dichiarazione e parziale creazione int array[][] = new int[10][]; • Dichiarazione, creazione e inizializzazione • String names[] = {"Tic","Tac"} /* equivalente a ... */ • String names[] = new String[2]; names[0] = "Tic"; names[1] = "Tac";
ERRORI CON LE MATRICI • Tentare di dimensionare una matrice nella (e non contestualmente alla) sua dichiarazione int list [50]; • Tentare di inizializzare una matrice prima di averla creata int list[]; for (int i=0 ; i<9 ; i++) { list[i] = i; } • Prima della sua creazione (operatore new) la matrice non esiste: la dichiarazione ha l'unico scopo di specificare il tipo della variabile (che comprende solo il numero delle dimensioni)
MATRICI COME CLASSI • Dalla classe Object, la capostipite di tutte le classi, deriva la classe Array, dotata di un metodo length ereditato dalle sue sottoclassi int a[][] = new int[10][3]; a.length; /* 10 */ a[0].length; /* 3 */ • Per ogni tipo (semplice o composto) esiste implicitamente una sottoclasse di Array che comprende tutte le matrici di oggetti di quel tipo (N.B. da Array non si possono derivare sottoclassi esplicitamente) • Se B è sottoclasse di A, allora B[] lo è di A[]
CLASSI, ATTRIBUTI E METODI • Esempio di classe public class MyClass { int i; /* attributo */ public MyClass () { /* metodo costruttore: ha lo i = 10; stesso nome della classe */ } public void Add_to_i (int j) { /* altro metodo */ i = i+j; } } • Ricordiamo che Java non adotta il modello a oggetti puro: "non tutti i dati sono oggetti"
FUNZIONI E POLIMORFISMO: OVERLOADING DI METODI • Variante dell'esempio precedente public class MyNewClass { int i; /* attributo */ public MyNewClass () { /* metodo costruttore: ha lo i = 10; stesso nome della classe */ } public MyNewClass (int j) { /* altro metodo costruttore i = j; diverso dal precedente */ } ..... } • Metodi omonimi devono essere distinguibili per la quantità e/o per il tipo degli argomenti
ATTRIBUTO this • Implicitamente presente in ogni oggetto, è sempre legato all'oggetto medesimo public class MyNewClass { int i; /* attributo */ public MyNewClass () { i = 10; } public MyNewClass (int i) { /* parametro */ this.i = i; /* disambiguazione */ } ..... } • Risolve omonimie e.g. tra attributi e parametri
CREAZIONE DI OGGETTI • Creazione e uso di un oggetto con MyClass MyClass mc;/* dichiarazione, non creazione */ mc = new MyClass(); /* creazione: l'attributo i vale 10 */ mc.i++; /* ora i vale 11 */ mc.Add_to_i(10); /* e ora i vale 21 */ • Creazione di un oggetto con MyNewClass MyNewClass mc0, mc1;/* dichiarazione, non creazione */ mc0 = new MyNewClass(); /* creazione: l'attributo i vale 10 */ mc0.i++; /* ora i vale 11 */ mc1= new MyNewClass(20); /* creazione: l'attributo i vale 20 */ mc1.i++; /* ora i vale 21 */
DISTRUZIONE DI OGGETTI • Java non supporta "distruttori" espliciti: gli oggetti non si distruggono, si "riciclano" • Un oggetto privo di puntatori incidenti non è più accessibile alle applicazioni e la memoria che esso occupa può essere "riciclata" String s; /* dichiarazione, non creazione */ s = new String ("abc"); /* creazione: s punta a "abc" */ s = "def"; /* "abc" non è più puntata da s */ • Il "riciclatore" (garbage collector, o GC) opera in un thread indipendente (i.e. "in parallelo" con altri thread, sia di utente che di sistema)
FINALIZZATORI DI OGGETTI • Un oggetto "riciclabile" (i.e. privo di puntatori incidenti) potrebbe trovarsi in uno stato poco "pulito" (e.g. in passato potrebbe aver aperto dei file che non sono stati ancora chiusi) • Prima di procedere alla fase cruenta, il GC invoca il metodo finalize di ciascun oggetto "riciclabile", definibile da utente protected void finalize () /* per protected vedi oltre */ { close (); } /*chiudi tutti i file aperti */ • Il metodo finalize esiste sempre: se non è stato ridefinito viene ereditato da Object
CLASSI: SINTASSI [Doc comment][Modifiers] class ClassName [extends SuperClassName] [implements InterfaceName [, InterfaceName]] {ClassBody} Doc comment - commento "di documentazione" Modifiers - uno o più dei qualificatori abstract, final, public/protected/private, native, synchronized, transient, volatile extends - la classe è sottoclasse di un'altra (e di una sola: ereditarietà singola) implements - la classe realizza una o più interfacce (può "simulare" ereditarietà multipla) ClassBody - gli attributi e i metodi della classe
CLASSI E SOTTOCLASSI • Le zebre come particolari tipi di cavallo... public class Horse { int Head, Tail, Legs, Body; public Horse () { Head = 1; Tail = 1; Legs = 4; Body = 1; } public void AddLegs (int Legs) { this.Legs += Legs;} } public class Zebra extends Horse { int Stripes; public Zebra (int Stripes) { this.Stripes = Stripes; } public void AddLegs (int Legs) /* ridefinizione */ { this.Legs += Legs + Stripes; } }
SOTTOCLASSI E super • Manipoliamo le zampe di una nuova zebra Zebra mz; mz = new Zebra(1000000000); /* ha 4 zampe */ mz.AddLegs(4); /* ora ne ha 1000000008 */ • Il vecchio metodo AddLegs è ancora usabile mz.super.AddLegs(4); /* ora ne ha 1000000012 */ • L'attributo super, implicitamente presente in ogni oggetto, permette di "ricuperare" un attributo/metodo da una (sopra)classe dopo che è stato ridefinito in una sua (sotto)classe
SOTTOCLASSI E CASTING • Proseguendo con l'esempio precedente Horse mh = (Horse)mz; /* ora è vista come cavallo */ mh.AddLegs(4); /* ora ha 1000000016 zampe */ (Zebra)mh.AddLegs(4); /* ora ne ha 2000000020 */ • Il cast da una classe a una sottoclasse (anche non diretta) è possibile se l'oggetto è davvero un esemplare della sottoclasse (il controllo è fatto a run-time); il viceversa è sempre OK • Il cast per linea di discendenza non diretta è un errore (il controllo è fatto a compile-time) • Il cast non altera gli oggetti: influisce solo sul modo di "osservare" un puntatore all'oggetto
METODI: SINTASSI [Doc comment][Modifiers]ReturnTypeMethodName (ParameterList) {MethodBody} Modifiers - uno o più dei qualificatori abstract, final, public/protected/private, native, synchronized, transient, volatile ReturnType - va omesso nei costruttori, ma va indicato (eventualmente void) negli altri casi; deve essere identico al tipo ritornato da metodi sovrascritti ParameterList - deve essere coerente con quella dei metodi sovrascritti MethodBody - le variabili locali devono essere inizializzate prima di essere usate
ACCESSI E CONDIVISIONE • Quattro tipi di diritti d'accesso • public void AnyOneCanAccess () { ... } • protected void OnlySubclassesCanAccess () { ... } • private void NoOneElseCanAccess () { ... } • void OnlyFromWithinMyPackage () { ... } L'ultimo tipo si chiama "friendly" • Attributi statici: condivisi da tutte le istanze; metodi statici: operano solo su dati statici class NewDocument extends Document { static int Version = 10; int Chapters; static void NewVersion () { Version++; } /* OK */ static void AddChapter () { Chapters++; } } /* KO */
TIPI DI CLASSE • Quattro tipi di classi • abstract: tra i vari metodi, deve contenerne almeno uno abstract, ma non può contenere metodi private o static; deve dare origine a sottoclassi; non può essere istanziata • final: termina una catena di classi-sottoclassi, non può dare origine a ulteriori sottoclassi • public: può essere usata senza formalità nel package che ne contiene la dichiarazione; disponibile anche in altri package, purché vi venga "importata" • synchronized: tutti i metodi interni sono synchronyzed • Classi astratte public abstract class Graphics { /* generica */ public abstract void DrawLine(int x1,y1,x2,y2); } public class VGA extends Graphics { /*specifica */ public void DrawLine(int x1,y1,x2,y2) { <codice per VGA> }}
INTERFACCE • Alternativa alle classi astratte: non richiede la derivazione esplicita di sottoclassi public interface AudioClip { void play (); /* avvia i'esecuzione */ void loop (); /* esegui ciclicamente una audio clip */ void stop (); } /* interrompi l'esecuzione */ class MyAudio implements AudioClip { void play () { <codice che implementa play> } void loop () { <codice che implementa loop> } void stop () { <codice che implementa stop> } } class YourAudio implements AudioClip { <codice> } • I metodi possono essere public o abstract, gli attributi public, static o final
OPERATORI E PRECEDENZA • Operatori (ordine di precedenza decrescente): . [] () ++ -- ! ~ instanceof * / % + - /* anche: String name = "Luigi" + "Stringa" */ << >> >>> < > <= >= == != /* ritornano un booleano */ & ^ | && || ? ... : ... = += -= *= /= &= |= ^= %= <<= >>= >>>=
ISTRUZIONI CONDIZIONALI • If • if (boolean) { statements; } else { statements; } • Case • switch (expr) { case tag1: statements; break; ..... case tagn: statements; break; default: statements; break; }
ISTRUZIONI ITERATIVE • For • for (init expr1 ; test expr2 ; incr expr3) { statements; } • While • while (boolean) { statements; } • Do • do { statements; } while (boolean) • Controllo di flusso • break [label] • continue [label] • return expr; • label: statement
FOR, SWITCH, CONTINUE E BREAK: PRECISAZIONI label: for (int i =0 , int j=0 ; i<10 && j<20; i++ , j++) { /* exp */ for (int z=0 ; z<100 ; z++) { /* scope è solo il for */ switch (expr) { case tag: statements; break; /* prosegue con penultima riga */ ..... default: statements; break label; } /* prosegue da label */ if (z==15) continue; /* prosegue il for z */ if (z==i+j) continue label; /* prosegue da label */ } }