Introduzione a Ereditariet e Polimorfismo applicate in Java
1 of 47
Downloaded 71 times
More Related Content
Java 02
1. Java Ereditariet e Polimorfismo applicate in Java Davide Ficano [email_address]
2. Ereditariet Polimorfismo Abbiamo detto che Ereditariet significa avere un oggetto base con un insieme di stati e comportamenti presenti anche in oggetti derivati Polimorfismo significa assumere significati specifici in diversi contesti
4. Classe Base Animale public class Animale { private String nome ; public Animale(String nuovoNome) { nome = nuovoNome; } public String getNome() { return nome ; } public String parla() { return "Errore: Animale generico" ; } } Non stiamo descrivendo nessuna specie animale particolare quindi non sappiamo qual'竪 il verso * Notare che non esiste il metodo setNome(...) per fare in modo che una volta dato il nome (nel costruttore) all'animale non lo si possa pi湛 cambiare
5. Classe specializzata Cane "extends" Animale public class Cane extends Animale { public Cane(String nome) { super (nome); } public String parla() { return "Ciao, io sono " + getNome() + " e faccio baubau" ; } } Viene usata la parola extends per derivare dalla classe Animale Il costruttore richiama quello della classe base tramite la parola riservata super Il metodo parla() viene ridefinito. Abbiamo applicato il Polimorfismo Viene richiamato il metodo getNome della classe base
6. Note su "extends" La parola riservata extends serve a derivare da una classe base Si pu嘆 derivare solo da una classe Avere l'ereditariet singola evita le ambiguit dovute alla presenta dello stesso metodo in due classi base: quale chiamo? public class Cane extends Animale, Lassie { } La Sintassi 竪 sbagliata perch辿 extends accetta solo una classe
7. Costruttori ed ereditariet Esempio 1 I costruttori non vengono ereditati sono comunque accessibili tramite la sintassi super (...) public class Cane extends Animale { ... ... } Non compila public class Cane extends Animale { public Cane(String nome) { super (nome); } } La classe a sinistra non compila perch竪 non "vede" il costruttore della classe base La classe a destra dichiara un costruttore uguale a quello della classe base e poi lo richiama con la sintassi super (...)
8. Utilizzo di super nei metodi /1 Anche i metodi possono richiamare super ma solo per riferirsi ad un metodo della classe base Significa che un metodo non pu嘆 richiamare un costruttore tramite super public class Cane extends Animale { public String parla() { super ( "fido" ); return ...; } } Non compila, c'e' errore alla linea nr 3. un costruttore non puo' essere richiamato in un metodo Domanda: Perch辿 un costruttore non pu嘆 essere richiamato in un metodo?
9. Utilizzo di super nei metodi /2 E' utile usare super nei metodi quando si vuole richiamare il metodo con lo stesso nome presente nella classe base public class Cane extends Animale { public String parla() { return "Ciao, io sono " + super .parla() + " e faccio baubau" ; } } Il metodo Cane.parla richiama il metodo Animale.parla la sintassi super.nomeMetodo pu嘆 essere usata in tutti i metodi ma risulta prolissa ed inutile ad eccezione del caso menzionato sopra
10. L'oggetto this Java possiede un oggetto che permette di fare riferimento all'istanza in cui ci si trova Si usa per risolvere problemi di ambiguit sulle variabili public Animale(String nome) { this . nome = nome; } public class Fattoria { public void addAnimale(Animale animale) { animale.setFattoria( this ); } } Oppure per passare "se stessi"
11. Polimorfismo (ancora!) Abbiamo visto che il metodo parla() della classe Cane ha un comportamento diverso da quello della classe base, 竪 un comportamento pi湛 specializzato il metodo parla() pu嘆 utilizzare quanto fatto nella classe base richiamando il metodo super.parla() public class Cane extends Animale { public String parla() { return "Ciao, io sono " + super .parla() + " e faccio baubau" ; } }
12. Incapsulamento e Polimorfismo /1 Esempio 2 E' molto utile utilizzare l'ereditariet e l'incapsulamento insieme Supponiamo che la nostra classe Animale gestisca il livello di fame public class Animale { private String nome ; private int fame = 0; public int getFame() { return fame ; } protected void setFame( int fame) { if (fame < 0) { this . fame = 0; } else if (fame > 10) { this . fame = 10; } else { this . fame = fame; } } } Notare che setFame() 竪 protected E' impossibile dare un valore non corretto all'attributo fame Domanda: Perch辿 竪 protected ?
13. Incapsulamento e Polimorfismo /2 Quando l'animale si muove la fame aumenta public void muovi() { if (possoAncoraMuovermi()) { aumentaFame(); } } Prima si verifica se pu嘆 ancora muoversi (linea 2) Se pu嘆 muoversi la fame aumenta (linea 3) Il metodo muovi() 竪 public quindi tutti possono richiamarlo
14. Incapsulamento e Polimorfismo /3 Il metodo possoAncoraMuovermi() 竪 public perch竪 pu嘆 essere utile al chiamante Il metodo aumentaFame() pu嘆 essere richiamato solo dalle classi derivate, questo impedisce che qualcuno lo chiami falsandone il valore public boolean possoAncoraMuovermi() { if ( fame < 10) { return true ; } return false ; } protected void aumentaFame() { ++ fame ; }
15. Incapsulamento e Polimorfismo /4 Facciamo muovere Fido public class TestCorsaFido { public static void main(String[] args) { Cane fido = new Cane( "Fido" ); while (fido.possoAncoraMuovermi()) { int fameAttuale = fido.getFame(); if (fameAttuale < 3) { System. out .println( "Sono pieno " + fameAttuale); } else if (fameAttuale < 6) { System. out .println( "Ho un languorino " + fameAttuale); } else { System. out .println( "Ho fame!!! " + fameAttuale); } fido.muovi(); } } } // chiude la classe
16. Incapsulamento e Polimorfismo /4 Il risultato della corsa di Fido Sono pieno 0 Sono pieno 1 Sono pieno 2 Ho un languorino 3 Ho un languorino 4 Ho un languorino 5 Ho fame!!! 6 Ho fame!!! 7 Ho fame!!! 8 Ho fame!!! 9
17. Incapsulamento e Polimorfismo /5 Esempio 3 La classe Cane riutilizza l'algoritmo della classe Animale per aumentare la fame ma ogni animale brucia energie a velocit diverse dobbiamo fare in modo che sia facile aggiungere nuovi animali alla nostra fattoria con comportamenti specializzati l'algoritmo dell'aumento fame sta nel metodo protected void aumentaFame() { ++ fame ; }
18. Incapsulamento e Polimorfismo /6 Fido diventa affamato pi湛 velocemente basta ridefinire cosa fa il metodo aumentaFame() nella classe Cane public class Cane extends Animale { public Cane(String nome) { super (nome); } protected void aumentaFame() { int fameAttuale = getFame(); setFame(fameAttuale + 3); } }
19. Incapsulamento e Polimorfismo /7 Senza modificare altro codice e rieseguendo il programma di test si ottiene Sono pieno 0 Ho un languorino 3 Ho fame!!! 6 Ho fame!!! 9
20. Incapsulamento e Polimorfismo /8 Il polimorfismo permette di trattare le classi derivate come se fossero tutte del tipo della classe base Cane braccobaldo = new Cane( "Braccobaldo" ); Animale fido = new Cane( "Fido" ); System. out .println(fido.getNome() + braccobaldo.getNome()); Alla linea 2 viene creato un oggetto Cane ma viene assegnato ad un oggetto di tipo Animale L'assegnazione 竪 lecita perch辿 Cane deriva da Animale Il contrario darebbe errore
21. Incapsulamento e Polimorfismo /9 Cosa succede se si vuole "convertire" un oggetto Animale generico in una classe derivata? Se l'assegnazione 竪 lecita, ovvero l'oggetto generico 竪 di tipo compatibile basta fare un cast (downcast) Se l'assegnazione non 竪 lecita viene generato un errore a runtime (non a compile time)
22. Incapsulamento e Polimorfismo /10 Cast - da classe base a derivata Il cast si ottiene mettendo tra parentesi il tipo desiderato davanti alla variabile da "convertire" Animale fido = new Cane( "Fido" ); Animale silvestro = new Gatto( "Silvestro" ); // e' corretto perche' silvestro e' di tipo gatto Gatto g = (Gatto)silvestro; // genera errore perche' fido e' un cane non un gatto Gatto g1 = (Gatto)fido;
23. Incapsulamento e Polimorfismo /11 operatore instanceof E' possibile testare un oggetto per scoprire il suo tipo utilizzando l'operatore instanceof Animale fido = new Cane( "Fido" ); if (fido instanceof Gatto) { System. out .println( "Fido e' un gatto" ); } else if (fido instanceof Cane) { System. out .println( "Fido e' un cane" ); } L'utilizzo di instanceof non 竪 una buona pratica OOP Il metodo 竪 particolarmente pesante da un punto di vita prestazionale
24. Override dei metodi Quando si ridefinisce un metodo in una classe derivata si dice che si fa override Il metodo aumentaFame() nella classe Cane 竪 quindi un override del corrispondente metodo della classe Animale "Fare override", "derivare", "specializzare" sono tutti sinomini Non si faccia confusione con overload dei metodi
25. Overload e override Overload due o pi湛 metodi della stessa classe hanno lo stesso nome ma prendono argomenti diversi Override un metodo presente nella classe base viene ridefinito in una o pi湛 classi derivate
26. Classi e metodi astratte /1 Esempio 4 All'inizio abbiamo definito la classe Animale con il metodo parla() Questo metodo non aveva nessuna utilit nella classe base Esiste un modo per dichiarare questo metodo senza implementazione Si forzano le classi derivate ad implementarlo (altrimenti non compilano) in modo da dargli la corretta implementazione Una classe astratta non pu嘆 essere istanziata
27. Classi e metodi astratti /2 Si crea una classe con il metodo parla astratto public class Animale { public String parla() { return "Errore: Animale generico" ; } } La classe diventa public abstract class Animale { public abstract String parla(); }
28. In Java tutto 竪 un oggetto Classe Object /1 In Java tutte le classi hanno una classe base implicita Questa classe di chiama Object e contiene dei metodi utili alla Java Virtual Machine Scrivere public class Animale extends Object { } public class Animale { } Equivale a scrivere
29. In Java tutto e' un oggetto Classe Object /2 La classe Object e' detta la radice della gerarchia delle classi Java Tra i metodi contenuti troviamo equals e toString public class Object { // Verifica se due oggetti sono uguali public boolean equals(Object obj) { } // Converte un oggetto in stringa public String toString() { } }
30. Polimorfismo per interfacce /1 Si 竪 visto che in Java si pu嘆 derivare da una sola classe Pu嘆 essere necessario definire un nuovo oggetto con caratteristiche provenienti da due oggetti diversi Un pappagallo vola, un cane nuota Si potrebbe creare una classe PuoVolare ed una PuoNuotare che estendono Animale ma perdono di genericit Anche un aereo "pu嘆 volare" e una barca "pu嘆 nuotare"
31. Polimorfismo per interfacce /2 Un pappagallo pu嘆 volare ma un'anatra pu嘆 sia volare che nuotare Utilizzando l'ereditariet abbiamo
32. Polimorfismo per interfacce /3 La classe PuoVolareENuotare 竪 necessaria ma appesantisce inutilmente la gerarchia delle classi Meglio sarebbe avere...
34. Polimorfismo per interfacce /4 Questo si realizza in Java utilizzando le interfacce (parola riservata interface ) Le interface sono simili alle classi astratte Esse hanno la dichiarazione dei metodi senza implementazione Possono avere solo metodi pubblic Non possono avere attributi Le classi derivate implementano le interfacce
35. Polimorfismo per interfacce /5 Le nostre classi diventano public interface PuoNuotare { public boolean nuota(); } public interface PuoVolare { public boolean vola(); }
36. Polimorfismo per interfacce /6 public class Cane extends Animale implements PuoNuotare { ... ... public boolean nuota() { return true ; } } public class Pappagallo extends Animale implements PuoVolare { ... ... public boolean vola() { return true ; } }
37. Polimorfismo per interfacce /7 public class Anatra extends Animale implements PuoNuotare, PuoVolare { ... ... public boolean nuota() { return true ; } public boolean vola() { return true ; } }
38. Quando si devono usare le interfacce Sempre!!! Le interfacce permettono di disaccoppiare l'implementazione dalla propria definizione Questo significa che e' facile sostituire il comportamento di una classe intervenendo solo sulla particolare implementazione Tutte le tecnologie Java (Servlet, EJB, JMS) sono basate sul concetto di interfaccia
39. I package /1 L'edizione Standard Edition di Java (SE) contiene circa 4000 tra classi ed interfacce L'edizione Enterprise Edition di Java (EE) contiene circa 300 tra classi ed interfacce Una tale mole di oggetti richiede una organizzazione razionale Le classi vengono organizzate in package Ogni package contiene le classi logicamente correlate
40. I package /2 I principali package in java sono java.lang String, Integer, Long java.lang.math Sin, Cos, min, max java.io File java.util Date, List java.sql Connection, Timestamp
41. I package /3 Se si vuole usare un metodo o una classe di un package bisogna importarlo nel proprio programma Le classi presenti in java.lang vengono importate implicitamente E' possibile, anzi caldamente consigliato , mettere le proprie classi in package Si possono importare tutti i package che si vuole, non esistono limiti
42. I package /4 package corso.java; import java.io.File; import java.util.Date; public class EsempioPackage { public static void main(String[] args) { System. out .println( "Radice quadrata " + Math. sqrt (144)); File f = new File( "a.txt" ); System. out .println( "Dimensione file " + f.length()); Date oggi = new Date(); System. out .println( "Oggi e' " + oggi); } }
43. I package /5 Un proprio package si definire con la parola riservata package Un package puo' avere livelli come una directory Ogni livello viene separato dal carattere punto java.lang
44. I package /6 Per utilizzare le classi di un package si deve fare l'import tramite la parola riservata import Non e' necessario fare import per le classi presenti in java.lang le classi presenti nello stesso package import java.io.File; File f = new File( "a.txt" );
45. Import singola classe Import intero package E' possibile effettuare l'import di una sola classe import java.io.File; import java.util.Date; import java.io.*; import java.util.Date; Oppure di un intero package (utilizzando la sintassi con asterisco ) L'import di un intero package 竪 una bad practice e andrebbe utilizzato sono in quei rarissimi casi in cui si rivela indispensabile
46. Package e classi con nomi uguali /1 Java ha due classi Date una usata per un uso generale (java.util.Date) una usata per l'accesso tramite SQL (java.sql.Date) Come faccio ad utilizzare entrambe nello stesso programma? import java.util.Date; import java.sql.Date; ** ERRORE DI COMPILAZIONE ** // oggetto di tipo java.util.Date Date oggi = new Date(); // Questa e' una SQL DATE ma come faccio a dirlo al compilatore? // oggetto di tipo java.sql.Date Date sqlOggi = new Date(oggi.getTime());
47. Package e classi con nomi uguali /2 Bisogna risolvere l'ambiguit in fase di dichiarazione della variabile import java.util.Date; Date oggi = new Date(); java.sql.Date sqlOggi = new java.sql.Date(oggi.getTime()); Si effettua l'import solo di una delle due (non importa quale) Si dichiara la seconda con il FQN (Full Qualified Name) ovvero tutto il nome package e della classe (come alla linea 3)