Principio dell’ Ereditarietà

Last Updated on 2 anni | Published: 18/04/2024

Principio dell' Ereditarietà

L’ ereditarietà è uno dei principi fondamentali della Programmazione Orientata agli Oggetti (OOP) che consente di creare nuove classi basate su classi esistenti, ereditando le loro proprietà (attributi) e comportamenti (metodi). In questo articolo, esploreremo il concetto di ereditarietà in Java, iniziando dalle spiegazioni di base per poi approfondire concetti più avanzati.

L’ ereditarietà è il processo attraverso il quale una nuova classe (chiamata sottoclasse o classe derivata) può ereditare attributi e metodi da una classe esistente (chiamata superclasse o classe base). Questo principio consente di creare una gerarchia di classi che rappresentano una relazione “è-un” tra gli oggetti, dove la sottoclasse è un tipo specifico della superclasse.

Nel contesto della programmazione OOP, l’ ereditarietà permette di riutilizzare il codice esistente, promuovendo la modularità, l’estensibilità e la manutenibilità del codice. Inoltre, facilita la progettazione e l’implementazione di sistemi software che rappresentano efficacemente le relazioni e le gerarchie di classi nel dominio del problema.

Per definire una classe derivata in Java, si utilizza la parola chiave extends seguita dal nome della classe base.

// Classe base

public class Veicolo {

// Metodo della classe base
       public void accendi() {
              System.out.println(“Il veicolo è stato  acceso.“);
       }

// Metodo della classe base
       public void spegni() {
              System.out.println(“Il veicolo è stato spento.“);
       }
}

// Classe derivata che estende la classe base
public class Auto extends Veicolo {
// Metodo della classe derivata
      public void guida() {
            System.out.println(“L’auto si muove.“);
      }
}
// Classe di prova con il metodo main

public class TestEreditarieta {

       public static void main(String[] args) {
              // Creazione di un oggetto della classe derivata Auto
             Auto miaAuto = new Auto();

             // Chiamata ai metodi ereditati dalla classe base Veicolo
             miaAuto.accendi();

            // Output: Il veicolo è stato acceso.
             miaAuto.spegni();

            // Output: Il veicolo è stato spento.

             // Chiamata al metodo della classe derivata Auto
             miaAuto.guida(); // Output: L’auto si muove.
       }
}

  • La classe Veicolo è la classe base che definisce due metodi accendi() e spegni().
  • La classe Auto è la classe derivata che estende la classe base Veicolo ed eredita i suoi metodi.
  • La classe TestEreditarieta è una classe di prova che contiene il metodo main per creare un oggetto della classe Auto e chiamare i metodi ereditati e il metodo specifico della classe Auto.

Un esempio semplice potrebbe riguardare la modellazione di diverse tipologie di prodotti in un negozio di elettronica. Immaginiamo di avere una classe Prodotto base e due sottoclassi Cellulari e Computer. Ecco come potrebbe essere implementato:

//Classe base Prodotto
public class Prodotti {
   protected String nome;
   protected double prezzo;
   public Prodotti(String nome, double prezzo) {
       this.nome = nome;
       this.prezzo = prezzo;
  }
  public String getNome() {
        return nome;
  }
   public double getPrezzo() {
       return prezzo;
   }
}
public class Cellulari extends Prodotti {
   private String marca;
 
  public Cellulari(String nome, double prezzo, String marca) {
      super(nome, prezzo);
      this.marca=marca;
  }
  @Override
  public String toString() {
      return “Cellulari [marca=” + marca + “,
      nome=” + nome + “, prezzo=” + prezzo + “]”;
  }
  public String getMarca() {
       eturn marca;
  }
}
public class Computer extends Prodotti {
     private String modello;
     public Computer(String nome, double prezzo, String modello) {
          super(nome, prezzo);
          this.modello=modello;
     }
    @Override
    public String toString() {
          return “Computer[modello=” + modello+ “,
                              nome=” + nome + “, prezzo=” + prezzo + “]”;
    }
    public String getMarca() {
       return modello;
    }
}
public class Start {
     public static void main(String[] args) {

          // Creazione di un oggetto Smartphone

             Cellulari apple= new Cellulari(“iPhone 13”, 850, “Apple”);
             Computer acer = new Computer(“Acer”,700.00,”GT45″);
          // stampando l’ oggetto ottengo lo stato degli attributi        
             // per la presenza di toString nelle classi derivate
          System.out.println(apple);
          System.out.println(acer);
      }
}

In Java, una classe può estendere una sola classe base alla volta, seguendo il principio dell’ ereditarietà singola. Questa scelta di progettazione è stata fatta per evitare le complessità e le ambiguità che potrebbero emergere dall’ereditarietà multipla.

L’ ereditarietà multipla, che permette a una classe di estendere più di una classe base, può portare a problemi di ambiguità e conflitti. Ad esempio, se due classi base forniscono metodi con la stessa firma (nome e parametri), potrebbe sorgere la domanda su quale metodo ereditare e come gestire eventuali conflitti.

Ereditarietà multiple

In Java, l’ ereditarietà multipla delle classi non è direttamente supportata. Tuttavia, è possibile simulare un certo tipo di ereditarietà multipla utilizzando le interfacce. Di seguito, un esempio semplice che illustra come una classe Uccello possa implementare due interfacce, Animale e Volante, per ereditare metodi da entrambe. 

// Interfaccia Volante
interface Volante {
       void vola();

}

// Interfaccia Animale
interface Animale {
       void mangia();
}
// Classe Uccello che implementa le interfacce Animale e Volante
class Uccello implements Animale, Volante {
       @Override
       public void mangia() {
                System.out.println(“L’uccello mangia.“);
       }       @Override
        public void vola() {
                System.out.println(“L’uccello vola.“);
         }

         public void canta() {
                System.out.println(“L’uccello canta.“);
         }
}

// Classe di prova con il metodo main

public class TestEreditarietaMultipla {

       public static void main(String[] args) {

         // Creazione di un oggetto della classe  Uccello
       Uccello mioUccello = new Uccello();

         // Chiamata al metodo ereditato dall’interfaccia Animale
       mioUccello.mangia(); // Output: L’uccello mangia.

         // Chiamata al metodo ereditato dall’interfaccia Volante
       mioUccello.vola();  // Output: L’uccello vola.

           // Chiamata al metodo della classe Uccello
        mioUccello.canta();  // Output: L’uccello canta.
       }
}

Ereditarietà e Override dei metodi

Il principio dell’ Override dei metodi consente alle classi derivate di fornire una specifica implementazione di un metodo ereditato dalla classe base, permettendo una maggiore flessibilità e polimorfismo nel design delle applicazioni. Di seguito un semplice esempio:

public class Veicolo {
    public void descrizione() {
       System.out.println(“Veicolo Trasporto Persone“);
    }
}

public class Auto extends Veicolo{
     @Override
     public void descrizione() {
        System.out.println(“Automobile Fiat“);
     }
}
import classi.Auto;
import classi.Veicolo;
public class Test {
     public static void main(String[] args) {
          Auto auto = new Auto();
          Veicolo veicolo = new Veicolo();
          veicolo.descrizione();
          auto.descrizione();
     }
}

Nell’esempio fornito, abbiamo una classe base Veicolo con un metodo descrizione(). La classe derivata Auto eredita il metodo descrizione() e lo modifica usando l’annotazione @Override. Questa annotazione è utilizzata per indicare che il metodo nella classe derivata sta sovrascrivendo un metodo della classe base. Quando si chiama il metodo descrizione() su un oggetto di tipo Auto, viene eseguito il metodo definito nella classe Auto, anche se l’oggetto è dichiarato come tipo Veicolo.

Nel prossimo articolo parleremo delle classi astratte che rappresentano un concetto fondamentale della programmazione OOP e servono come base per creare altre classi  ………

LABORATORIO

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *