Il Polimorfismo: descrizione ed esempi

DOMANDA:

Che cos'è il polimorfismo in Java?



RISPOSTA:

Uno degli elementi fondamentali della programmazione ad oggetti (e quindi anche di Java) è proprio il polimorfismo. Con questo termine, scomponendo ad intuito, possiamo dedurne il significato: poli - morfismo -> multi-forme (non formalizziamoci sull'etimologia del termine). 

Proprio come suggerito dall'intuito, il polimorfismo altro non è che la capacità di un oggetto di poter assumere diverse forme.

Il concetto è spesso ostico ai neofiti della programmazione ad oggetti, ma in realtà, con un esempio pratico si può cominciare a capire la potenza di questo sistema.


ESEMPIO

Un leone, una mucca e un cavallo avranno tutti e tre la capacità di emettere un proprio verso.

Vediamolo nel dettaglio:
package polimorfismo;

public class Leone {
   public void emettiVerso(){
      System.out.println("RUGGITO");
   }
}
package polimorfismo;

public class Mucca {
   public void emettiVerso(){
      System.out.println("MUGGITO");
   }
}
package polimorfismo;

public class Cavallo {
   public void emettiVerso(){
      System.out.println("NITRITO");
   }
}
In questi esempi il modo per far emettere un verso ai diversi "animali" è questo:
package polimorfismo;

public class Fattoria {
   public static void main(String args[]){
      Leone leo = new Leone();
      leo.emettiVerso();

      Mucca muu = new Mucca();
      muu.emettiVerso();

      Cavallo cav = new Cavallo();
      cav.emettiVerso();
   }
}
L'output sarà banalmente:
RUGGITO
MUGGITO
NITRITO

Fin qui niente di particolare. Ma vediamo come sfruttare il polimorfismo.

Creiamo un'interfaccia Animale che comprenda tutti i diversi animali della nostra Fattoria.
package polimorfismo;

public interface Animale {
   public void emettiVerso();
}
Con questa interfaccia ci siamo assicurati che tutti gli Animale sappiano emettere un verso (quindi abbiano il metodo emettiVerso()).

Facciamo in modo che il Leone, la Mucca e il Cavallo siano degli Animale implementandone l'interfaccia:
package polimorfismo;

public class Leone implements Animale {
   public void emettiVerso(){
      System.out.println("RUGGITO");
   }
}
package polimorfismo;

public class Mucca implements Animale {
   public void emettiVerso(){
      System.out.println("MUGGITO");
   }
}
package polimorfismo;

public class Cavallo implements Animale {
   public void emettiVerso(){
      System.out.println("NITRITO");
   }
}
Adesso modifichiamo leggermente la classe main Fattoria:
package polimorfismo;

public class Fattoria {
   public static void main(String args[]){
      Animale leo = new Leone();
      leo.emettiVerso();

      Animale muu = new Mucca();
      muu.emettiVerso();

      Animale cav = new Cavallo();
      cav.emettiVerso();
   }
}
L'output sarà ugualmente:
RUGGITO
MUGGITO
NITRITO

Nella pratica i tre oggetti di diverso tipo sono tutti e tre degli Animale generici, ma conservano le proprie specifiche caratteristiche.


Il polimorfismo risulta utile in moltissimi casi.

Un esempio evidente è in un array:
package polimorfismo;

public class FattoriaTest {
   public static void main(String args[]){
      Animale[] arrayAnimali = new Animale[5];
      arrayAnimali[0] = new Mucca();
      arrayAnimali[1] = new Mucca();
      arrayAnimali[2] = new Cavallo();
      arrayAnimali[3] = new Mucca();
      arrayAnimali[4] = new Leone();

      for(Animale anim: arrayAnimali)
         anim.emettiVerso();
   }
}
L'output sarà:
MUGGITO
MUGGITO
NITRITO
MUGGITO
RUGGITO

Come si può notare non abbiamo dovuto effettuare cast, instance of o altri controlli. L'oggetto Animale sa assumere automaticamente più forme e quindi diversi comportamenti. Questa capacità è detta polimorfismo ed è comune a diversi linguaggi ad oggetti.

NOTA: negli esempi abbiamo implementato il polimorfismo attraverso l'utilizzo di interfacce. Avremmo potuto farlo allo stesso modo creando la super classe (e non l'interfaccia) Animale e poi estendendola con i tre diversi oggetti Leone, Mucca e Cavallo.

Il polimorfismo è possibile grazie al binding dinamico di Java. Infatti il compilatore non decide quale metodo chiamare nella fase di compilazione, ma si limita a creare delle tabelle che consentono al programma di scegliere il metodo giusto a runtime in base alla classe dell’oggetto.


Commenti

Post popolari in questo blog

Arrotondamento e troncamento in Java

Eclipse: Shortcuts (scorciatoie) da tastiera

Strutture dati: List, Set, Map

Creare un eseguibile Java