capitolo 4
DESCRIPTION
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 - PowerPoint PPT PresentationTRANSCRIPT
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 classepublic 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 precedentepublic 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 MyClassMyClass 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 MyNewClassMyNewClass 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 zebraZebra mz;
mz = new Zebra(1000000000); /* ha 4 zampe */
mz.AddLegs(4); /* ora ne ha 1000000008 */
• Il vecchio metodo AddLegs è ancora usabilemz.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 precedenteHorse 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] ReturnType MethodName
(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 astrattepublic 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 */
}
}