In questa lezione • Interfacce (in Java) – keyword interface – Polimorfismo con interfacce • NB: nessuna correlazione con il conce@o di interfacce grafiche Interfaccia di una classe • Insieme delle operazioni (metodi) e dei daD public – I membri privaD non fanno parte dell’interfaccia – L’implementazione non fa parte dell’interfaccia • Viene proge@ata al momento della definizione della classe – definisce i servizi “esportaD” e quindi uDlizzabili dalle altre parD del sistema/programma 1 Interfaccia come “contra@o” – Desiderata: • Se l’implementazione cambia ma l’interfaccia non cambia, il resto del sistema non deve essere modificato public class Time { private int timeInMilliSec; public class Time { private int hours; private int minutes private int secs; //public methods public int getMilliSeconds(){ return timeInMilliSec; } //same public methods //but with different bodies public int getMilliSeconds(){ return secs * 1000 + minutes * 60000 + hours * 60 * 60000; } } } 3 La keyword interface in Java – Java consente di definire interfacce come enDtà proprie indipendentemente dalle classi – Una interface è definita come una classe completamente astra@a • Viene definita la signature di ogni metodo, ma non l’implementazione Definisce una interfaccia, non una classe 4 NB: l’implementazione public interface IStack { dei metodi non è presente public int size(); public boolean isEmpty(); public Object top(); public void push(Object elt); public Object pop(); } 2 Usare le interfacce in Java – Possiamo dire al compilatore che una classe viene realizzata per implementare una data interfaccia. Per esempio: public class MyStack implements IStack {… – Il compilatore controllerà che la classe fornisca tu@a l’implementazione della specifica definita dall’interfaccia • Ovvero che la classe implemenD tuX i metodi dell’interfaccia • NB: a meno che non si traX di una classe astra@a, che quindi rimanda l’implementazione completa alle so@oclassi concrete • NB: la classe può avere altri metodi oltre a quelli che servono per implementare l’interfaccia 5 Esempio (i/ii) public interface IStack { public int size(); public boolean isEmpty(); public void push(Object o); public Object top(); public Object pop(); } Definisce i servizi Dpici di una stru@ura daD con accesso LIFO (Last In First Out) 6 3 Esempio (ii/ii) public class ArrayStack implements IStack { private Object items[]; private int top = -1; Fornisce un’implementazione dell’interfaccia IStack public ArrayStack(int maxSize) { items = new Object[maxSize]; } public int size(){ return top + 1; } public boolean isEmpty(){ return top == -1; } public void push(Object o){ items[++top] = o; } public Object top(){ return items[top]; } public Object pop(){ return items[top--]; } public void print(){System.out.println(“…”);} } 7 interface vs. class – Una definizione di classe (class) può includere • Variabili di istanza o di classe (staDc) • Metodi di istanza o di classe (staDc), con implementazione – Una definizione di interfaccia (interface) include solo • Metodi di istanza, solo signature (no body) • Definizione di costanD 8 4 D: Quali definizioni sono legali? public interface MyInterface1 { public int a1; public int a2 = 0; private void m1(); public void m2(); public void m3(){} public static void m4(); … …Risposte • public int a1; – Error: …the blank final field would have not been iniDalized • public int a2 = 0; • private void m1(); – Error: …illegal modifier for m1(); only public/abstract permi@ed – NB: public e abstract sono comunque implicitamente definiD sempre in una interface) • public void m2(); • public void m3(){} – Error: …abstarct methods do not specify a body • public staDc void m4(); – Error: …illegal modifier for m4… 5 D: Quali definizioni sono legali? public interface MyInterface1 { public int a2 = 0; public void m1(); public void m2(); public void m3(); … class User implements MyInterface1 { public static void main(String args[]){ System.out.println(a2); a2 = 5; } private void m1(){} public void m2(){} public void m3(); } …Risposte public interface MyInterface1 { public int a2 = 0; public void m1(); public void m2(); public void m3(); … class User implements MyInterface1 { public static void main(String args[]){ System.out.println(a2); a2 = 5; //impossibile ridefinire una costante } private void m1(){} //non si può ridurre la visibilità public void m2(){} public void m3(); //bisogna fornire un’implementazione … 6 Polimorfismo con interfacce • In Java le interfacce possono essere usate come Dpo di dato polimorfo, analogamente a quanto visto per le classi astra@e – un reference definito del Dpo di un’interfaccia può riferirsi dinamicamente agli oggeX delle classi che implementano l’interfaccia IStack s; s = new ArrayStack(20); s.push(new Integer(3)); //dynamic binding s.print(); //errato perché s è di tipo IStack – NB: La dichiarazione “ArrayStack implements IStack…” garanDsce per il reference s il successo del dynamic binding per ogni metodo dell’interfaccia IStack 13 Gerarchie di interfacce • L’ereditarietà può essere applicata alle interfacce, così come alle classi interface InterfaceName2 extends InterfaceName1{ // Body of InterfaceName2 } • L’interfaccia “figlia” eredita tu@e le definizioni di metodi e costanD dell’interfaccia “genitore” • Una classe che implemenD l’interfaccia figlia deve definire tuX i metodi della gerarchia • Le gerarchie di ereditarietà delle classi e delle interfacce sono completamente disDnte e non si sovrappongono 14 7 Implementare un’interfaccia “figlia” interface I1 { public void m1(); } interface I2 extends I1{ public void m2(); } class C1 implements I2{ //C1 deve forzatamente implementare sia m2 che m1 public void m1(){……} public void m2(){……} … Ereditarietà mulDpla • Possibilità di definire classi che ereditano il comportamento di un insieme di altre classi. Ad esempio: class SmallProduct { public void buy(){…} } class ElectronicDevice { private void buy(){…} } class MP3Player extends SmallProduct,ElectronicDevice{ ... } • Strumento uDle, ma… fonte di ambiguità se lo stesso metodo venisse ereditato da più classi. Ad esempio: MP3Player player = new MP3Player(); player.buy(); //quale implementazione?? 8 Diamond problem • ParDcolare ambiguità determinata da gerarchie di erediterietà mulDpla con antenaD comuni abstract class Product { public void buy(){…} } class SmallProduct extends Product{ public void buy(){…} //override } class ElectronicDevice extends Product{ } class MP3Player extends SmallProduct,ElectronicGadget{ } MP3Player player = new MP3Player(); player.buy(); //quale implementazione?? Ereditarietà mulDpla in Java • L’ereditarietà mulDpla NON È supportata in Java per le gerarchie di classi!!! • L’ereditarietà mulDpla non causa problemi nelle gerarchie di ereditarietà delle interfacce – anche se un metodo viene definito più volte, poiché l’implementazione non è data, tu@e le definizioni sono sempre equivalenD • NB: a@enzione a non confondere overriding con i casi di overloading – Java consente che una classe estenda UNA SOLA altra classe, ma implemenD interfacce MULTIPLE 18 9 Esempio • RivisiDamo l’esempio del diamon problem, ma ipoDzzando di aver a che fare con interfacce interface Product { public void buy(); } interface SmallProduct extends Product{ public void buy(); } interface ElectronicDevice extends Product{ } class MP3Player implements SmallProduct,ElectronicGadget{ La classe MP3Player public void buy(){…} deve fornire l’implementazione } del metodo buy() MP3Player player = new MP3Player(); player.buy(); //nessuna ambiguità!! Ricapitolando… – Un’interfaccia è analoga ad una classe astra@a: specifica quali metodi vengono forniD, ma non ne dà alcuna implementazione – Dire che una classe ”implements” un’interfaccia è equivalente a firmare un contra@o che stabilisce che la classe deve fornire un’implementazione per i metodi specificaD –NB: Java non compila il programma altrimenD – Possiamo usare (polimorficamente) reference del Dpo di un’interfaccia e, a@raverso di essi, invocare i metodi dell’interfaccia – Le interfacce perme@ono di realizzare una forma, sebbene minimale, di ereditarietà mulDpla. L’ereditarietà mulDpla non è supportata dalle classi in Java, ma è possibile che una classe implemenD mulDple interfacce 20 10 Interfacce ESERCIZI E APPROFONDIMENTI Interfacce: Esercizio 1 • • • • • • • • Si consideri il sistema formato da una Stampante, la CartucciaColori e un Display. Ogni stampante è idenDficata da un nome (String) e una porta (int) La Stampante fornisce il metodo stampa() che usa una Cartuccia a 4 colori (nero, blu, magenta, giallo). Quando viene invocato, il metodo stampa() consuma un’unità di ogni colore dalla Cartuccia, e resDtuisce true. Se qualche colore non è disponibile, il metodo stampa invia il segnale CARTUCCIA_IN_ESAURIMENTO al Display e resDtuisce ancora true. Se la Cartuccia è vuota, il metodo stampa() invia il segnale CARTUCCIA_VUOTA al Display e resDtuisce false. Si faccia l’ipostesi che sia le cartucce che i display siano forniD da diversi produ@ori (ovvero ne esistono di diverse marche), e che diversi display e cartucce possano essere istallaD in una stampante, in sosDtuzione di quelli correnD, a@raverso i metodi istallaCartuccia e istallaDisplay della classe Stampante La classe Stampante risolve il problema di poter comunicare con cartuccie e display di diversi produ@ori definendo delle interfacce che tuX i produ@ori devono implementare Per esempio, si implemenD un display che, quando riceve il messaggio CARTUCCIA_IN_ESAURIMENTO, visualizza a video un messaggio per avvisare che la stampa è parziale. Quando riceve il messaggio CARTUCCIA_VUOTA, visualizza a video il messaggio di sosDtuire la cartuccia Si implemenD un caso di test che me@e in azione il sistema e ne verifica il funzionamento 11 Interfacce: Esercizio 2 • • Si realizzi un’interfaccia PrintableDocument che definisce i metodi: – header(), footer(): resDtuiscono una stringa da uDlizzare come intestazione e piè di pagina – pages(int): riceve un intero che rappresenta la dimensione corrente della pagina in termini del numero massimo di cara@eri per pagina, e resDtuisce un array di stringhe, dove ogni stringa corrisponde ad una pagina da stampare Si realizzi la classe Printer che definisce il metodo print() che riceve come parametro un PrintableDocument, stampa a video il documento come sequenza Page <num> \n <header> \n\n <pagina> \n\n <footer> \n Page <num>…”, • • dove \n indica un cara@ere di ritorno a capo, <num> è il numero di ogni pagina, mentre <header>, <pagina> e <footer> sono o@enuD invocando i metodi del documento da stampare. print() resDtuisce il numero di cara@eri stampaD Si personalizzino le classi File e Folder (esercizio Polimorfismo) in modo da implementare l’interfaccia Printable Document Si realizzi un test che crea alcuni File e Folder, li stampa a@raverso un ogge@o Printer e verifica il risultato con un assertEquals. Interfacce: Esercizio 3 • Si noD che nella java standard library (package java.lang) viene definita l’interfaccia interface Comparable { int compareTo(Object o); } • • • • • Si noD inoltre la classe java.uDl.Arrays ha metodi per ordinare array di oggeX di qualsiasi Dpo, a pa@o che tali oggeX implenDno l’interfaccia Comparable Si riconsideri adesso la gerarchia Poligono-­‐Triangolo-­‐Re@angolo (Esercizio della lezione sulle classi astra@e) e si faccia in modo che un array di poligoni possa essere ordinato in base all’area dei poligoni che conDene Si facciano dei test per verificare il funzionamento Si riconsiderino adesso le classi File e Folder dell’esercizio precedente e, sfru@ando il metodo di java.uDl.Arrays, si faccia in modo che i Folder ordinino i File per dimensione ogni volta che un nuovo File viene inserito in un Folder Si facciano dei test per verificare il funzionamento 12 Interfacce: Esercizio 4 • Si noD che la classe Object ( java standard library) definisce il metodo: – protected Object clone()// Creates and returns a copy of this object • Il metodo clone è “protected” quindi non invocabile, ma le classi che estendono Object possono ridefinirlo come “public” e renderlo quindi accessibile. In questo caso, la libreria standard spiega che: – By convenDon, the returned object should be obtained by calling super.clone. – The method clone for class Object performs a specific cloning operaDon. First, if the class of this object does not implement the interface Cloneable, then a CloneNotSupportedExcepDon is thrown. Otherwise, this method creates a new instance of the class of this object and iniDalizes all its fields with exactly the contents of the corresponding fields of this object, as if by assignment; the contents of the fields are not themselves cloned. Thus, this method performs a "shallow copy" of this object, not a "deep copy" operaDon – By convenDon, the object returned by this method should be independent of this object (which is being cloned). To achieve this independence, it may be necessary to modify one or more fields of the object returned by super.clone before returning it. … • L’interfaccia clonable è definita come: interface Clonable{} //NB: nessun metodo • Si implemenD e si tesD il metodo clone per la classe stampante dell’esercizio 1 13