Il linguaggio Java Gianpaolo Cugola [email protected] Gianpaolo Cugola 1 Sgomberiamo il campo dai dubbi • Cosa non è Java: – Non è un linguaggio per “animare” il WWW – Non è una versione ridotta del C+ + – Non è lo strumento che segnerà la fine di Microsoft • Cosa è Java – Un moderno linguaggio di programmazione OO… – Orientato alla programmazione di applicazioni “network-centric” Gianpaolo Cugola Gianpaolo Cugola 2 Perché Java • Il problema: – L’inadeguatezza dello schema di sviluppo tradizionale (binary distribution) in ambienti distribuiti e multipiattaforma • La soluzione: – Java, un linguaggio O.O. per lo sviluppo di applicazioni “architecture independent”, robuste, adattabili, scalabili ed efficienti Gianpaolo Cugola 3 Java: caratteristiche generali - 1 • Familiare: – La sintassi di Java ricalca la sintassi del C++ – Un programmatore C++ non incontra grosse difficoltà ad imparare il linguaggio Java • Semplice: – Programmare usando Java è molto più semplice di programmare usando altri linguaggi OO (C++) • Un buon programmatore Java è più produttivo di un buon programmatore C+ + Gianpaolo Cugola Gianpaolo Cugola 4 Java: caratteristiche generali - 2 • Object-oriented: – Java è un linguaggio OO “puro” con ereditarietà, binding dinamico ed oggetti gestiti tramite riferimenti – Il costrutto delle “interfaces” fornisce le potenzialità dell’ereditarietà multipla senza alcun problema di duplicazione di codice • Portabile: – La specifica del linguaggio non contiene componenti “implementation dependent” Gianpaolo Cugola 5 Java: caratteristiche generali - 3 • Architecture neutral: – L’applicazione viene compilata in un linguaggio intermedio (Java ByteCode) che viene interpretato – L’interprete nasconde le caratteristiche peculiari dell’hardware e del sistema operativo – Lo stesso codice “oggetto” può essere eseguito su tutte le piattaforme per le quali venga fornito un interprete Java (attualmente Solaris, Windows NT/ 95, MacOS, OS/ 2, AIX, e Linux) Gianpaolo Cugola Gianpaolo Cugola 6 Java: caratteristiche generali - 4 • Dinamico: – Le fasi di loading e linking avvengono a run-time • Robusto: – Java è un linguaggio fortemente tipizzato con numerose caratteristiche che diminuiscono la possibilità di introdurre errori nelle applicazioni, tra le quali: • assenza di puntatori • abbondanza di controlli run-time (rispetto dei limiti degli array, controlli di tipo, controlli sul codice caricato dinamicamente, ecc.) • gestione automatica della memoria (garbage collecting) Gianpaolo Cugola 7 Java: caratteristiche generali - 5 • Multi-threaded: – Java supporta la gestione dei “thread” a livello di linguaggio, oltre che di macchina virtuale, fornendo la possibilità di creare facilmente applicazioni concorrenti Gianpaolo Cugola Gianpaolo Cugola 8 L’ambiente Java Byte code Loader Java Source Java Compiler Java Byte Code Byte code Verifier Byte Code moves through network or file system Interpreter Machine Code Generator (JIT) Run time Hardware/OS Gianpaolo Cugola 9 Java - il primo programma file: HelloWorld.java public class HelloWorld { public static void main(String args[]){ System.out.println(“Hello world!”); } } Gianpaolo Cugola Gianpaolo Cugola 10 Compilazione ed esecuzione c:\classes>javac HelloWorld.java c:\classes>java HelloWorld HelloWorld! c:\classes> Gianpaolo Cugola 11 La struttura di un programma Java nozioni preliminari • Un programma Java è organizzato come un insieme di classi • Classi diverse possono essere raggruppate all’interno della stessa “Compilation unit” • Il programma principale è rappresentato da un metodo speciale della classe il cui nome coincide con il nome del programma Gianpaolo Cugola Gianpaolo Cugola 12 Java - il primo programma grafico File: HelloWorldWindow.java import java.awt.*; package examples, class HelloWorldWindow { public static void main(String args[]) { Frame f=new Frame("HelloWorldWindow"); f.add(new Label("HelloWorld!",Label.CENTER),"Center"); f.pack(); f.setVisible(true); } } Gianpaolo Cugola 13 Compiliazione ed esecuzione c:\classes>cd examples c:\classes\examples>javac HelloWorldWindow.java c:\classes\examples>cd .. c:\classes>java examples.HelloWorldWindow c:\classes> Gianpaolo Cugola Gianpaolo Cugola 14 La struttura di un programma Java • Package – Ogni package contiene una o più compilation unit – Il package introduce un nuovo ambito di visibilità dei nomi • Compilation unit – Ogni compilation unit contiene una o più classi o interfaccie delle quali una sola pubblica • Classi e interfaccie • Relazioni con il file system – package ⇔ directory – compilation unit ⇔ file Gianpaolo Cugola 15 Il linguaggio Java in dettaglio • Costrutti per la programmazione “in the small” – Il type system di Java • Tipi predefiniti e relative costanti ed operatori • Tipi definiti dall’utente – Dichiarazione di variabili – Istruzioni per il controllo di flusso • Costrutti per la programmazione “in the large” – Classi – Interfaccie – Packages Gianpaolo Cugola Gianpaolo Cugola 16 I commenti in Java // questo è un commento che termina con la fine della linea /* questo è un commento che può spaziare su più linee */ Gianpaolo Cugola 17 Identificatori • Gli identificatori (nomi di classi, variabili, attributi, metodi ecc.) sono sequenze alfanumeriche che: – Devono iniziare con una lettera o con il carattere '_' – Il resto dell’identificatore può contenere sia lettere che numeri, o il carattere '_' – Non devono coincidere con una delle parole riservate • Esempi Ok: HelloWorld helloWorld h ello_world __prova __PROVA prova1 prova1a prova2 Errati: 2prova +prova prova + hello-world hello? prova-1 • Java è “case sensitive” Gianpaolo Cugola Gianpaolo Cugola 18 Le costanti • Costanti intere: 123 256789L 0xff34d 0xcafebabeL 03477 07352367L • Costanti reali: 123.75 0.12375e+3 12375.0e-2f 1.0E-5 123.75f 123.75F 123.75D • Costanti boolean: true false • Costanti carattere: ’a’ ’%’ ’\t’ ’\n’ ’\\’ ’\’’ ’\123’ • Costanti di tipo stringa: ”prova” ”prova\n” ”prova( \”aaa\” )” Gianpaolo Cugola 19 Il tipe system di Java • Java è un linguaggio fortemente tipizzato • Distinguiamo tra: – tipi primitivi – tipi “riferimento” Gianpaolo Cugola Gianpaolo Cugola 20 I tipi primitivi • Tipi numerici: – – – – – – byte: short: int: long: float: double: 8 bit 16 bit 32 bit 64 bit 32 bit, secondo specifica IEEE754 64 bit, secondo specifica IEEE754 • Altri tipi: – boolean: – char: true o false 16 bit, carattere Unicode Gianpaolo Cugola 21 Operatori per i tipi numerici - 1 • Operatori unari – operatori “di segno” +x -x – incremento e decremento (prefissi e/ o postfissi) ++x --x x++ x-- – operatore di complemento binario (valido per soli tipi “interi”): ~x Gianpaolo Cugola Gianpaolo Cugola 22 Operatori per i tipi numerici - 2 • Operatori binari – validi per tutti i tipi numerici x+y x-y x*y x/y x%y – validi per i soli tipi “interi” x<<y x>>y x>>>y x&y x|y x^y • Operatori di confronto x==y x!=y x<y x>y x<=y x>=y Gianpaolo Cugola 23 Operatori per il tipo boolean • Operatore unario – negazione logica: !x • Operatori binari – operatori standard x&y x|y x^y – operatori con semantica condizionale x&&y x||y – operatori di confronto x==y Gianpaolo Cugola Gianpaolo Cugola x!=y 24 Operatori per il tipo char • Operatori di confronto x==y x!=y x<y x>y x<=y x>=y Gianpaolo Cugola 25 Gli operatori di auto assegnamento • E` possibile usare l’operatore: x ?= y al posto di un qualsiasi operatore ? che sia lecito utilizzare nell’espressione: x=x?y • Tale espressione equivale alla precedente x?=y • Esempi: x+=5 x*=2 Gianpaolo Cugola Gianpaolo Cugola equivale a equivale a x=x+5 x=x*2 26 Altri operatori • Operatore condizionale – si applica a tutti i tipi <condizione> ? <valore1> : <valore2> • L’assegnamento come operatore x=y=3 (y=3)==3 • L’operatore di concatenazione tra stringhe – si applica a tutti i tipi ”pippo”+2 ”pippo”+2.54 Gianpaolo Cugola 27 I tipi riferimento • Tipi array • Tipi definiti dall’utente Gianpaolo Cugola Gianpaolo Cugola 28 Tipo array • Dato un tipo T (predefinito o definito dall’utente) un array di T è definito come: T[] • Similmente sono dichiarati gli array multidimensionali: T[][] T[][][] … • Esempi: int[] float[][] Persona[] Gianpaolo Cugola 29 Tipi definiti dall’utente • Classi • Interfaccie ... i dettagli nel seguito Gianpaolo Cugola Gianpaolo Cugola 30 Dichiarazione e inizializzazione di variabili • Dichiarazione int i; int i,j; Persona p; float f1,f2; double d; • Inizializzazione int i=0; int i=0, j=4; Persona p=new Persona(); float f1=1.23f, f2=127.2f; double d=1.23; Gianpaolo Cugola 31 Dichiarazione e inizializzazione di variabili: gli array • Dichiarazione: int[] ai1, ai2; float[] af1; double ad[]; Persona[][] ap; • Inizializzazione: int[] ai={1,2,3}; double[][] ad={{1.2, 2.5}, {1.0, 1.5}} Gianpaolo Cugola Gianpaolo Cugola 32 Dichiarazione di array ed allocazione di memoria • La dichiarazione di un array non alloca spazio per gli elementi dell’array • L’allocazione si realizza dinamicamente tramite l’operatore new int[] i=new int[10], j; float[][] f=new float[10][10]; Persona[] p=new Persona[30]; j=new int[30]; che alloca però solo lo spazio per l’array, non per i suoi elementi (tranne nel caso di tipi predefiniti). Gianpaolo Cugola 33 Istruzioni per il controllo del flusso • • • • Sequenza di istruzioni Blocco di istruzioni Istruzione condizionale Cicli – – – – Ciclo con uscita all’inizio Ciclo con uscita alla fine Ciclo con uscita in mezzo Ciclo con contatore • Istruzione switch Gianpaolo Cugola Gianpaolo Cugola 34 Sequenza e blocco • Una sequenza di istruzioni è composta da una serie di istruzioni separate dal carattere ‘;’ a=3; b=4; c=a*b+3; • Un blocco di istruzioni è composto da una sequenza di istruzioni racchiuse da parentesi graffe {a=1; b=3; c=a+128;} – Un blocco di istruzioni è equivalente ad una singola istruzione Gianpaolo Cugola 35 Istruzione condizionale • Permette la scelta tra due diversi percorsi del flusso di controllo • Sintassi if(<condizione>) <istruz.1> [else <istruz.2>] • Il ramo else si lega all’istruzione if più vicina Gianpaolo Cugola Gianpaolo Cugola 36 Istruzione condizionale: esempi • Esempio 1: if(x==5) System.out.println(“x vale 5”); System.out.println(“fatto!”); • Esempio 2: if(x>0 && y>0) System.out.println(“x ed y positivi”); else if(x>0) System.out.println(“x positivo”); else if(y>0) System.out.println(“y positivo”); else System.out.println(“nessuno dei due positivi”); System.out.println(“fatto!”); Gianpaolo Cugola 37 Istruzione condizionale: esercizio • Si scriva un programma che legge un intero su riga di comando corrispondente ad un mese e restituisce il numero di giorni in quel mese – Si faccia uso dell’istruzione: Integer.parseInt(<string>) che restituisce un intero a partire da una stringa Gianpaolo Cugola Gianpaolo Cugola 38 Ciclo con condizione all’inizio • Sintassi: while(<condizione>) <istruzione> ; • Esempio int r=5; while(r>0) { System.out.println(“HelloWorld!”); r--; } Gianpaolo Cugola 39 Ciclo con condizione all’inizio: esercizio • Si scriva un programma per il calcolo del fattoriale • Si scriva un programma che legge un intero da riga di comando e stampa a video un “triangolo” formato da ‘*’ con base di lunghezza pari all’intero letto – Si osservi che l’istruzione: System.out.print(<string>) stampa la stringa passata come parametro senza andare a capo Gianpaolo Cugola Gianpaolo Cugola 40 Ciclo con condizione alla fine • Sintassi: do <istruzione> while(<condizione>) • Esempio: int r=5; do { System.out.println("HelloWorld!"); r--; } while(r>0); Gianpaolo Cugola 41 Ciclo con condizione alla fine: esercizio • Si scriva un programma che esegue il prodotto tra due numeri secondo l’algoritmo delle somme ripetute. Si faccia uso del ciclo con condizione alla fine Gianpaolo Cugola Gianpaolo Cugola 42 Ciclo con condizione in mezzo • E` possibile uscire da un ciclo tramite l’istruzione break – Sfruttando questo fatto è possibile creare cicli con condizione di terminazione in mezzo • Esempio: java.io.FileInputStream s=new FileInputStream(“a”); while(true) { b=s.read(); if(b==0) break; System.out.println(b); } Gianpaolo Cugola 43 Ciclo con condizione in mezzo: esercizio • Si scriva un programma che legge un file byte a byte salvando il contenuto in un array di 500 byte. Il programma deve terminare quando la fine del file è stata raggiunta o quando si sono letti 500 byte – Si osservi che l’istruzione: s.read() applicata ad un FileInputStream s restituisce -1 quando si è raggiunta la fine del file. Gianpaolo Cugola Gianpaolo Cugola 44 Ciclo con contatore • Sintassi: for(<istr1>; <condiz>; <istr2>) <istr3> • Equivalente a: <istr1>; while(<condiz>) { <istr3> <istr2> } Gianpaolo Cugola 45 Ciclo con contatore: esempi • Esempio 1: int r; for(r=0; r<5; r++) System.out.println(“HelloWorld!”); • Esempio 1 bis: for(int r=0; r<5; r++) System.out.println(“HelloWorld!”); • Esempio 2: for(int r=0; r<10; r+=2) System.out.println(“r=”+r); Gianpaolo Cugola Gianpaolo Cugola 46 Ciclo con contatore: esercizio • Si scriva un programma che stampa a video le tabelline (da 1 a 10). Si faccia uso del ciclo con contatore Gianpaolo Cugola 47 Ancora sull’istruzione break • Sintassi completa di un istruzione break: – break [<label>] • Significato: – restituisce il controllo all’istruzione che include quella con il break e che è marcata con l’identificatore specificato • Esempio: ciclo1 : while(true) { ciclo2 : while(true) { leggi(x); if(x==1) break ciclo1; else break ciclo2; } } Gianpaolo Cugola Gianpaolo Cugola 48 Istruzione switch • Sintassi: switch(<espressione>) { case <espr_cost_1> : [<istr_1>;]* case <espr_cost_2> : [<istr_2>;]* ... case <espr_cost_n> : [<istr_n>;]* [ default : [<istr>;]* ] } • L’espressione all’interno dello switch deve essere di tipo char, byte, short, o int Gianpaolo Cugola 49 Istruzione switch: esempio public class Prova { static public void main(String[] args) { int x=Integer.parseInt(args[0]); switch(x) { case 1: case 2: case 3: System.out.println(“x pari a 1,2 o 3”); break; case 4: System.out.println(“x pari a 4”); break; default: System.out.println(“x diverso da 1,2,3 o 4”); } } } Gianpaolo Cugola Gianpaolo Cugola 50 Istruzione switch: esercizio • Si scriva un programma che legge un intero su riga di comando corrispondente ad un mese e restituisce il numero di giorni in quel mese. Si usi l’istruzione switch Gianpaolo Cugola 51 Conversioni automatiche di tipo • Promozioni byte short int long -> -> -> -> short, int, long, float, double int, long, float, double long, float, double float or double float char -> -> double int, long, float, double Gianpaolo Cugola Gianpaolo Cugola 52 Conversioni forzate: casting • È possibile forzare una conversione di tipo attraverso l’operatore di casting: (<tipo>)<espressione> • Tra tipi semplici sono consentite le seguenti conversioni (con perdita di informazione) short char int long float double byte -> -> -> -> -> -> -> byte, byte, byte, byte, byte, byte, char char short short, short, short, short, char char, int char, int, long char, int, long, float Gianpaolo Cugola 53 I costrutti OO per la programmazione “in the large” • • • • • Classi Interfaccie Ereditarietà Polimorfismo e binding dinamico Packages Gianpaolo Cugola Gianpaolo Cugola 54 Definizione di una nuova classe • Una nuova classe viene definita nel seguente modo: class <nome classe> { <lista di definizioni di attributi e metodi> } • Esempio: class Automobile { ... } Gianpaolo Cugola 55 Definizione di attributi • Gli attributi di una classe definiscono la struttura dello stato degli oggetti che vi appartengono • Ogni attributo è definito usando la stessa sintassi usata per la definizione delle variabili locali • Esempio class Automobile { String colore, marca, modello; int cilindrata, numPorte; boolean accesa; } Gianpaolo Cugola Gianpaolo Cugola 56 Definizione di metodi • I metodi di una classe definiscono il comportamento degli oggetti che vi appartengono • Ogni metodo è definito come segue: <tipo val. rit.> <nome.>([<dic. par. formali>]) <corpo> • Il tipo void viene utilizzato per metodi che non ritornano alcun valore Gianpaolo Cugola 57 Definizione di metodi: esempio class Automobile { String colore, marca, modello; int cilindrata, numPorte; boolean accesa; void accendi() {accesa=true;} boolean puoPartire() {return accesa;} void dipingi(String col) {colore=col;} void trasforma(String ma, String mo) { marca=ma; modello=mo; } } Gianpaolo Cugola Gianpaolo Cugola 58 Visibilità dei nomi • I nomi degli attributi e dei metodi sono visibili all’interno di tutta la classe • Le variabili dichiarate in un blocco sono visibili solo all’interno del blocco • Le variabili locali ad un metodo (o i parametri formali) possono mascherare gli attributi • Le variabili dichiarate all’interno di un blocco possono mascherare le variabili dichiarate all’interno di blocchi più esterni Gianpaolo Cugola 59 Oggetti • Ogni variabile il cui tipo sia una classe (o un interfaccia) contiene un riferimento ad un oggetto • Nuovi oggetti sono costruiti usando l’operatore new • Esempio: Automobile a=new Automobile(); • Ad una variabile di tipo riferimento può essere assegnato il riferimento null Gianpaolo Cugola Gianpaolo Cugola 60 Accesso ad attributi e metodi di un oggetto • L’accesso ad attributi e metodi di un oggetto per il quale si abbia un riferimento si effettua tramite la “notazione punto” • Esempio: Automobile a=new Automobile(); a.accendi(); a.dipingi(“Blu”); System.out.println(“Num. porte: “+a.numPorte); Gianpaolo Cugola 61 Accesso ad attributi e metodi di un oggetto da metodi dello stesso oggetto • Nella definizione di un metodo ci si riferisce ad attributi e metodi dell’oggetto sul quale il metodo sia stato invocato direttamente (senza notazione punto) • Esempio class Automobile { ... boolean puoPartire() {return accesa;} void dipingi(String col) {colore=col;} ... } • La pseudo-variabile this contiene un riferimento all’oggetto corrente e può essere utilizzata per aggirare eventuali mascheramenti Gianpaolo Cugola Gianpaolo Cugola 62 La pseudo-variabile this: esempio class Automobile { String colore, marca, modello; int cilindrata, numPorte; boolean accesa; void accendi() {accesa=true;} boolean puoPartire() {return accesa;} void dipingi(String col) {this.colore=col;} void trasforma(String marca, String modello) { this.marca=marca; this.modello=modello; } } Gianpaolo Cugola 63 Classi: esercizio • Si definisca l’insieme di classi necessarie per descrivere un computer (Monitor, Tastiera, Mouse, Case, Scheda) Gianpaolo Cugola Gianpaolo Cugola 64 Passaggio parametri • I parametri il cui tipo sia uno dei tipi semplici sono passati per copia • I parametri il cui tipo sia un tipo riferimento (classi, interfacce e array) sono passati per copia del riferimento – ovvero, gli oggetti sono passati per riferimento Gianpaolo Cugola 65 Overloading • All’interno di una stessa classe possono esservi più metodi con lo stesso nome purché si distinguano per numero e/ o tipo dei parametri – Il tipo del valore di ritorno non basta a distinguere due metodi • Esempio: class C { int f() {...} int f(int x) {...} // corretto void f(int x) {...} // errato } Gianpaolo Cugola Gianpaolo Cugola 66 Creazione e distruzione di oggetti • La creazione di un oggetto comporta due operazioni: – l’allocazione della memoria necessaria a contenere l’oggetto e – l’inizializzazione dello spazio allocato Quest’ultima operazione è svolta dal costruttore • A differenza del C+ + in Java non è necessario deallocare esplicitamente gli oggetti creati con una operazione new. Di ciò si occupa il garbage collector Gianpaolo Cugola 67 Costruttori • Nella definizione di una classe è possibile specificare uno o più costruttori • Il costruttore è un metodo particolare che ha lo stesso nome della classe – Nel caso ci siano più costruttori, essi si distinguono perché differiscono per numero e/ o tipo dei parametri – Per i costruttori non viene indicato il tipo del risultato (è implicito nel nome del costruttore) • Il costruttore di default (senza parametri) viene fornito dal compilatore a meno che non si definiscano altri costruttori Gianpaolo Cugola Gianpaolo Cugola 68 Costruttori: esempio class Automobile { String colore, marca, mod ello; int cilindrata, numPorte; boolean accesa; Automobile() { colore=marca=modello= null; cilindrata=numPorte=0; } Automobile(String colore, String marca, String modello) { this.colore=colore; this.marca=marca; this.modello=modello; } void accendi() {accesa= true;} boolean puoPartire () {return accesa;} void dipingi(String col) {this.colore=col;} } Gianpaolo Cugola 69 Ancora sui costruttori • È possibile invocare un costruttore dall’interno di un altro tramite la notazione: this(<elenco di parametri attuali>); • Esempio: class Persona { String nome; int eta; Persona(String nome) {this.nome=nome; eta=0;} Persona(String nome, int eta) { this(nome); this.eta=eta; } } Gianpaolo Cugola Gianpaolo Cugola 70 Classi e costruttori: esercizio • Esercizio 1: – Si costruisca una classe che implementa uno stack di interi di dimensione fissa (stabilita in fase di costruzione) • Esercizio 2: – Si modifichi la classe precedente (introducendone altre se necessario) per implementare uno stack di dimensione variabile (allocazione dinamica di memoria) • Esercizio 3: – Si usi la classe precedente per realizzare un programma che legge un file byte a byte e lo inverte Gianpaolo Cugola 71 Metodi e attributi di classe • Sintassi: static <definizione dell’attributo o metodo> • Un attributo di classe è condiviso da tutti gli oggetti della classe • Si può accedere ad un attributo di classe senza bisogno di creare un oggetto tramite la notazione: <nome classe>.<nome attributo> • Un metodo di classe può essere invocato senza bisogno di creare un oggetto tramite la notazione: <nome classe>.<nome metodo>(<par. attuali>) Gianpaolo Cugola Gianpaolo Cugola 72 Metodi e attributi di classe: vincoli • Un metodo static può accedere ai soli attributi e metodi static • Un metodo convenzionale può accedere liberamente a metodi ed attributi static Gianpaolo Cugola 73 Metodi e attributi di classe: esempio class Shape { static Screen screen=new Screen(); // si noti l’iniz. static void setScreen(Screen s) {screen=s;} void show(Screen s) {setScreen(s); ...} } ... Shape.setScreen(new Screen()); // corretto Shape.show(); // errato, show è un metodo normale Shape s1=newShape(), s2=new Shape(); Screen s=new Screen(); s1.setScreen(s); // corretto, si possono chiamare // metodi static su oggetti // in questo punto s2.screen==s1.screen==s Gianpaolo Cugola Gianpaolo Cugola 74 Attributi costanti • È possibile definire attributi costanti tramite la notazione: final <definizione di attributo>=<valore> • Esempio class Automobile { int colore; final int BLU=0, GIALLO=1,...; void dipingi(int colore) {this.colore=colore;} } ... Automobile a=new Automobile(); a.BLU=128; // errato System.out.println(“BLU=“+a.BLU); // corretto Gianpaolo Cugola 75 Esercizio • È corretto affermare che tramite attributi e metodi di classe e attributi costanti è possibile definire funzioni, variabili e costanti globali? Gianpaolo Cugola Gianpaolo Cugola 76 La gerarchia di ereditarietà • Le classi di un sistema OO sono legate in una gerarchia di ereditarietà • Data una classe C, una sottoclasse di C si definisce tramite la notazione: class K extends C { <definiz. di attr. e metodi> } • La sottoclasse eredita tutti gli attributi ed i metodi della sopraclasse • Java supporta solo ereditarietà semplice Gianpaolo Cugola 77 La classe Object • In mancanza di una differente indicazione, una classe Java estende la classe Object • La classe Object fornisce alcuni metodi tra i quali vale la pena citare i seguenti: public boolean equals(Object); protected void finalize(); public String toString(); Gianpaolo Cugola Gianpaolo Cugola 78 Overriding • Una sottoclasse può aggiungere nuovi attributi e metodi ma anche ... • ridefinire i metodi delle sue sopraclassi • Esempio: class AutomobileElettrica extends Automobile { boolean batterieCariche; void ricarica() {batterieCariche=true;} void accendi() { if(batterieCariche) accesa=true; else accesa=false; } } Gianpaolo Cugola 79 La pseudo variabile super • All’interno di un metodo che ridefinisce un metodo della sopraclasse diretta ci si può riferire al metodo che si sta ridefinendo tramite la notazione: super.<nome metodo>(<lista par. attuali>) • Esempio: class AutomobileElettrica extends Automobile { ... void accendi() { if(batterieCariche) super.accendi(); else System.out.println(“Batterie scariche”); } } Gianpaolo Cugola Gianpaolo Cugola 80 Ereditarietà e costruttori • I costruttori non vengono ereditati • All’interno di un costruttore è possibile richiamare il costruttore della sopraclasse tramite la notazione: super(<lista di par. attuali>) posta come prima istruzione del costruttore • Se il programmatore non chiama esplicitamente un costruttore della sopraclasse, il compilatore inserisce automaticamente il codice che invoca il costruttore di default della sopraclasse Gianpaolo Cugola 81 Ereditarietà: esercizio • Si definisca una classe Persona e due sottoclassi Uomo e Donna. La classe Persona deve avere un metodo chiSei() che stampa il nome della persona. Nelle sottoclassi tale metodo deve essere ridefinito perché stampi anche il sesso Gianpaolo Cugola Gianpaolo Cugola 82 Information hiding in Java • Attributi e metodi di una classe possono essere: – pubblic • sono visibili a tutti • vengono ereditati – protected • sono visibili solo alle sottoclassi • vengono ereditati – private • sono visibili solo all’interno della stessa classe • non sono visibili nelle sottoclassi Gianpaolo Cugola 83 Information hiding: esempio class Automobile { private String colore, marca, modello; private int cilindrata, numPorte; private boolean accesa; public Automobile() { colore=marca=modello=null; cilindrata=numPorte=0; } public Automobile(String col, String ma, String mo) {colore=col; marca=ma; modello=mo;} public void accendi() {accesa=true;} public boolean puoPartire() {return accesa;} public void dipingi(String col) {colore=col;} } Gianpaolo Cugola Gianpaolo Cugola 84 Information hiding: esercizio • Si modifichi l’esercizio precedente introducendo le dichiarazioni di visibilità per i membri delle classi Gianpaolo Cugola 85 Classi e metodi astratti • Un metodo astratto è un metodo per il quale non viene specificata alcuna implementazione • Una classe è astratta se contiene almeno un metodo astratto • Non è possibile creare istanze di una classe astratta • Le classi astratte sono molto utili per introdurre della astrazioni di alto livello Gianpaolo Cugola Gianpaolo Cugola 86 Classi e metodi astratti: esempio abstract class Shape { static Screen screen; Shape(Screen s) {screen=s;} abstract void show(); } class Circle extends Shape { void show() { ... } } ... Shape s=new Shape(); // errato Circle c=new Circle(); // corretto Gianpaolo Cugola 87 Classi astratte: esercizio • Nell’esercizio precedente si introduca una classe astratta OggettoConNome, sopraclasse di Persona Gianpaolo Cugola Gianpaolo Cugola 88 Classi e metodi final • Se vogliamo impedire che sia possibile creare sottoclassi di una certa classe la definiremo final • Esempio: final class C {...} class C1 extends C // errato • Similmente, se vogliamo impedire l’overriding di un metodo dobbiamo definirlo final • Esempio: class C { final void f() {...} } class C1 extends C { void f() {...} // errato } Gianpaolo Cugola 89 Ereditarietà ed array • Se X è una sopraclasse di Y allora l’array X[] è “sopra-array” dell’array Y[] – Lo stesso vale per gli array multidimensionali • Tale scelta non è type safe • Esempio: void f(X[] ax) { ax[0]=new X(); } ... f(new Y[10]); Gianpaolo Cugola Gianpaolo Cugola 90 I limiti dell’ereditarietà semplice • L’ereditarietà semplice non permette la descrizione di numerose situazioni reali • Esempio: – Supponiamo di avere una classe Giocattolo ed una classe Automobile. In assenza di ereditarietà multipla non posso definire la classe AutomobileGiocattolo Gianpaolo Cugola 91 I problemi dell’ereditarietà multipla • In presenza di ereditarietà multipla è possibile ereditare due o più metodi con la stessa “signature” da più sopraclassi. Ciò determina un conflitto tra implementazioni diverse K C1 C2 f (int i) : int f (int i) : int f (int i) : int C1 C2 C C Gianpaolo Cugola Gianpaolo Cugola 92 Ereditarietà semplice vs. ereditarietà multipla: la soluzione di Java • Distinguere tra una gerarchia di ereditarietà (semplice) ed una gerarchia di implementazione (multipla) ... • introducendo il costrutto delle interfacce • In tal modo è possibile distinguere tra l’uso dell’ereditarietà al fine di riutilizzare il codice e l’uso al fine di descrivere una gerarchia di tipi Gianpaolo Cugola 93 Interfacce • Una interfaccia è una classe priva di attributi non costanti ed i cui metodi sono tutti pubblici ed astratti • Sintassi: interface <nome> { <lista di definizione di metodi privi di corpo> } Gianpaolo Cugola Gianpaolo Cugola 94 Interfacce ed ereditarietà • Una interfaccia può ereditare da una o più interfacce • Sintassi: interface <nome> extends <nome1>,..,<nomen> {...} • La gerarchia di ereditarietà tra interfacce definisce una gerarchia di tipi Gianpaolo Cugola 95 Interfacce: esercizio • In che senso una interfaccia descrive un tipo meglio di una classe? Gianpaolo Cugola Gianpaolo Cugola 96 La gerarchia di implementazione • Una classe può implementare una o più interfacce – se la classe non è astratta deve fornire una implementazione per tutti i metodi presenti nelle interfacce che implementa – altrimenti la classe è astratta • Sintassi: class <nome> implements <nome1>,..,<nomen> {...} Gianpaolo Cugola 97 Polimorfismo • Polimorfismo è la capacità per un elemento sintattico di riferirsi a elementi di diverso tipo • In Java una variabile di un tipo riferimento T può riferirsi ad un qualsiasi oggetto il cui tipo sia T o un sottotipo di T • Similmente un parametro formale di un tipo riferimento T può riferirsi a parametri attuali il cui tipo sia T o un sottotipo di T Gianpaolo Cugola Gianpaolo Cugola 98 Polimorfismo: esempio class Automobile {...} class AutomobileElettrica extends Automobile {...} class Parcheggio { private Automobile buf[]; private int nAuto; public Parcheggio(int dim) {buf=new Automobile[dim];} public void aggiungi(Automobile a) {buf[nAuto++]=a;} } ... Automobile a=new AutomobileElettrica(); Parcheggio p=new Parcheggio(100); p.aggiungi(new AutomobileElettrica()); Gianpaolo Cugola 99 Polimorfismo ed interfacce • Una interfaccia può essere utilizzata come tipo di una variabile • Una siffatta variabile potrà riferirsi ad un qualsiasi oggetto che implementi l’interfaccia (polimorfismo) • Esempio: interface OggettoCheSpara { spara(); } class Pistola implements OggettoCheSpara {...} OggettoCheSpara o=new Pistola(); o.spara(); Gianpaolo Cugola Gianpaolo Cugola 100 Polimorfismo: tipo statico e tipo dinamico • In presenza di polimorfismo distinguiamo tra il tipo statico ed il tipo dinamico di una variabile (o di un parametro formale) – La regola del polimorfismo prima enunciata obbliga il tipo dinamico ad essere un sottotipo (proprio o meno) del tipo dinamico Gianpaolo Cugola 101 Polimorfismo e binding dinamico • In Java, a fronte della invocazione x.f(x1,...,xn), l’implementazione scelta per il metodo f dipende dal tipo dinamico di x e non dal suo tipo statico Gianpaolo Cugola Gianpaolo Cugola 102 Binding dinamico: esempio class Persona { private String nome; public Persona(String nome) {this.nome=nome;} public void chiSei() { System.out.println(“Ciao, io sono “+nome); } } class Uomo extends Persona { public Uomo(String nome) {super(nome);} public void chiSei() {super.chiSei(); System.out.println(“sono un maschio”);} } ... Persona p=new Uomo(“Giovanni”); p.chiSei(); OUTPUT: Ciao, io sono Giov anni sono un maschio Gianpaolo Cugola 103 Polimorfismo e binding dinamico: esercizio • Si costruisca uno stack di persone e lo si usi per conservarvi tanto uomini quanto donne. Al termine si verifichi l’effetto del binding dinamico richiamando il metodo chiSei() su tutti gli oggetti conservati Gianpaolo Cugola Gianpaolo Cugola 104 Conversioni forzate tra tipi riferimento: casting • È possibile forzare esplicitamente la conversione da un tipo riferimento T ad un sottotipo T1 purché: – Il tipo dinamico dell’espressione che convertiamo sia un sottotipo di T1 • Esempio: Object o=new AutomobileElettrica(); Automobile a=o; // errato, Object non è un // sottotipo di Automobile Automobile a=(Automobile) o; // corretto (casting) Gianpaolo Cugola 105 Casting: esercizio • Si spieghi perché il casting è fondamentale per implementare contenitori generici (stack di Object ecc.) Gianpaolo Cugola Gianpaolo Cugola 106 Package ed information hiding • Package e visibilità degli attributi e dei metodi – Attributi e metodi di una classe C per i quali non sia dichiarato alcun tipo di visibilità sono visibili solo all’interno di classi che appartengano allo stesso package di C – Tale costrutto gioca un ruolo analogo alla dichiarazione di friendship in C++ • Package ed importazione di classi – Un package contiene un insieme di classi pubbliche ed un insieme di classi private – Solo le classi pubbliche si possono importare in altri package • Package e compilation unit – Ogni compilation unit contiene classi appartenenti allo stesso package – Una compilation unit contiene una sola classe pubblica (per default la prima) ed eventualmente altre classi private Gianpaolo Cugola 107 Il package java.lang • Il package java.lang contiene classi di uso molto frequente (String, Object, ecc.) • Non è necessario importare le classi appartenenti al package java.lang prima di utilizzarle Gianpaolo Cugola Gianpaolo Cugola 108