I tranelli del polimorfismo in Java
Il polimorfismo non è tutto rose e fiori, spesso può riservare qualche brutta sorpresa. Diamo uno sguardo a qualche tecnica avanzata, ma anche ad alcuni dei possibili tranelli che attendono il programmatore meno smaliziato.


Come sappiamo, il polimorfismo consente di utilizzare, oggetti di classi diverse, purché derivino dalla stessa classe. Ecco un esempio:

 
public class Animale
{
   public void interroga() 
   {
     System.out.println(“Grunt”);
   }
}
public class Ghepardo extends 
Animale 
{
    public void interroga() 
   {
      System.out.println(“Groar!”);
   }
}
public class Muflone extends Animale 
{
    public void interroga() 
   {
      System.out.println(“MOOOO!”);
   }
   public void salta() 
   {
       System.out.println(“hop!”);
    }
}
public class Zoo 
{
    private final static int MAX_BESTIE = 6; 
 // dimensione dello zoo (è una costante)
    private Animale[] bestie = new 
Animale[MAX_BESTIE];  // array di animali
     private int numero = 0; 
// contatore degli animali presenti
     public boolean aggiungiAnimale(Animale a)
     {
        if(numero < MAX_BESTIE) 
        {
           // inserisci l’animale nello zoo
           bestie[numero] = a;
           // incrementa il numero degli
                           animali nello zoo  
           numero++;
           return true;
        }
        else
        return false;
     }
     public void concerto() 
  {
      for (int i = 0; i < MAX_BESTIE; 
i++) 
     {   // scorri l’intero zoo
          if (bestie[i] == null)  
// se finisci le bestie, esci
          return;
          bestie[i].interroga();
      }
   }
   public static void main(String[] 
args)
   {
       Zoo z = new Zoo();
       boolean spaziolibero;
       Animale nuovo; 
       do 
       {
         double d = Math.random();
         if (d > 0.5)
     nuovo = new Muflone();
   else
     nuovo = new Ghepardo();
   spaziolibero = z.aggiungiAnimale(nuovo); 
// proponi l’animale allo zoo
 } while (spaziolibero);  // continua
                         finché lo zoo non 
rifiuta l’animale
     // e ora... concerto!
     z.concerto();
  }
}

Questo programma è una versione leggermente modificata di uno degli esempi dell’articolo del mese scorso. Abbiamo una classe base Animale che definisce un metodo interroga(), e due classi derivate Ghepardo e Muflone che ridefiniscono questo metodo. La classe Zoo è un semplice contenitore di animali. Il metodo main() di Zoo è il nostro programma di test: crea animali scegliendo a caso le due razze disponibili, e li inserisce nello Zoo con il metodo aggiungiAnimale(). Questa operazione è possibile perché ciascun animale subisce un “cast verso l’alto” quando viene passato ad aggiungiAnimale(): che l’oggetto sia un Ghepardo o un Muflone, viene trattato semplicemente come un Animale. Alla fine, il programma chiama il metodo concerto(), che a sua volta chiama il metodo interroga() di ciascun Animale nello Zoo. Questo è un esempio di polimorfismo. Il metodo concerto() non distingue un Ghepardo da un Muflone. Addirittura, il metodo non sa nemmeno che queste classi esistono: per lui, esistono solo oggetti di classe Animale. Eppure, grazie al meccanismo del “binding dinamico”, per ciascun Animale viene invocata la versione specifica del metodo interroga(). Questo meccanismo ci permette di costruire sistemi espandibili. In questo caso, possiamo aggiungere nuove sottoclassi di Animale, e ciascuna sottoclasse può fornire la sua implementazione del metodo interroga(). La classe Zoo continuerà a gestire tutte le sottoclassi di Animale senza fare una piega (nel programma fa anche la sua apparizione la parola chiave final, che spiegheremo meglio tra poco)