back to top

Polimorfismo Java: overload e override dei metodi

Il polimorfismo è un altro concetto fondamentale della programmazione ad oggetti e risulta essere anche quello più ostico per la piena comprensione della sua utilità. Il concetto di polimorfismo è relativo proprio al suo significato ovvero avere più forme, più aspetti. Per chiarire il concetto possiamo fare un semplice esempio di applicazione del polimorfismo nella vita reale: quando facciamo riferimento ad un computer probabilmente useremo lo stesso termine (computer, appunto) sia per identificare un computer desktop, un portatile o un netbook. Questo tipo di generalizzazione viene effettuata in quanto gli oggetti cui abbiamo fatto riferimento sostanzialmente effettuano le stesse operazioni… ma queste operazioni vengono fatte da oggetti con forme diverse (polimorfismo).

Una volta chiarito il senso del polimorfismo, andiamo ad analizzare il polimorfismo per i metodi.

Polimorfismo dei metodi

Dal punto di vista implementativo il polimorfismo per i metodi si ottiene utilizzando l’overload e l’override dei metodi stessi. Quando abbiamo parlato dei metodi abbiamo detto che ogni metodo è identificato dal nome che gli assegnamo, adesso estendiamo questa definizione dicendo che un metodo è univocamente determinato se prendiamo in considerazione sia il suo nome che la lista di tutti i suoi parametri. Ciò permette, di fatto, di avere all’interno di una classe più metodi che hanno lo stesso nome, ma con parametri diversi. L’overload quindi si basa sulla scrittura di più metodi identificati dallo stesso nome che però hanno, in ingresso, parametri di tipo e numero diverso. Riprendiamo in mano una delle nostre classi di esempio "OperazioniSuNumeri" e immaginiamo di implementare, con l’overload, due metodi che effettuano la somma uno tra due numeri interi e un altro su numeri di tipo float. Avremo dunque:

public class OperazioniSuNumeri {
  public int somma(int x, int y) {
    return x+y;
  }

  public float somma(float x, float y) {
    return x-y;
  }
}

Dal punto di vista implementativo dunque non ci dovremo assolutamente preoccupare di effettuare controlli su i due numeri d’ngresso e di conseguenza richiamare il metodo appropriato per effettuare la somma. Dal punto di vista del codice, invece, la nostra implementazione della classe sarà la seguente:

public class Implementazione {

  OperazioniSuNumeri numeri = new OperazioniSuNumeri();
  sommaInteri = numeri.somma(3,4);
  System.out.println("La somma tra interi è:");
  System.out.println(sommaInteri);

  sommaFloat = numeri.somma(2.1,8.3);
  System.out.println("La somma tra float è:");
  System.out.println(sommaFloat);
}

Il codice sopra scritto funzionerà perfettamente in quanto ogni volta che viene invocato il metodo somma, verranno controllati il tipo di parametri che gli sono stati passati ed in base a questa scelta, automaticamente, verrà richiamato il metodo appropriato.

Abbiamo utilizzato, inconsapevolmente, anche il polimorfismo quando abbiamo richiamato il metodo System.out.println(). Nella prima chiamata, infatti, abbiamo passato al metodo una stringa e subito sotto gli abbiamo passato una variabile intera senza che ciò generasse nessun errore. Ciò vuol dire che il Java ci mette a disposizione più implementazioni diverse per il metodo System.out.println() che è, appunto, un metodo polimorfo!

Con il termire override si intende una vera e propria riscrittura di un certo metodo di una classe che abbiamo ereditato. Dunque, necessariamente, l’override implica ereditarietà. Per capirne il significato vero e proprio facciamo une esempio basato su una classe più volte utilizzata in questa guida: la classe "Dipendente". La classe "Dipendete" sarà così strutturata (volutamente sono stati omessi i metodi set e get per gli attributi "nome" e "cognome"):

public class Dipendente{

  private String nome;
  private String cognome;
  private int oreLavorativeMensili;
  private int retribuzioneOraria;

  public int getOreLavorativeMensili(){
    return oreLavorativeMensili;
  }
    
  public int getRetribuzioneOraria(){
    return restribuzioneOraria;
  }

  public int stipendio(){
    return oreLavorativeMensili * retribuzioneOraria;
  }  
}

Adesso ereditiamo la classe, creandone un’altra che modella il "RespondabileDiProgetto" che, oltre ad uno stipendio fisso, ha un attributo che rappresenta un bonus di produzione. Dunque la retribuzione di questo dipendente sarà data dalla somma dello stipendio base con l’eventuale bonus. Quindi il codice per la classe sarà il seguente:

public class ResponsabileDiProgetto extends Dipendente {

  private int bonus;

  public int stipendio(){
    int stipendioBase=(getOreLavorativeMensili() * getRetribuzioneOraria());
    return stipendioBase + bonus;
  }
}

Con l’override, quindi, è possibile ridefinire un metodo di una classe più generalista adattandolo così alla classe più specialista mantenendo comunque una coerenza per quanto riguarda la semantica del metodo che avrà lo stesso identico nome.

Pubblicità
Articolo precedente
Articolo successivo