Quando abbiamo parlato dell’ereditarietà non abbiamo considerato la possibilità di derivare una classe da più classi padre, la cosiddetta ereditarietà multipla.
Dobbiamo subito dire che in Java non esiste l’ereditarietà multipla e quindi non si può scrivere qualcosa del tipo:
class SottoClasse extends SuperClasse1, Superclasse2 {…}
Qualcuno si potrebbe chiedere allora come possiamo fare ad esempio a definire una sottoclasse di una classe che abbia anche la capacità di avere la gestione dei thread. In Java si utilizzano le interfacce per questo scopo, infatti può essere considerata come un particolare tipo di classe e come queste ha un nome e sono scritti in file con estensione .java e risiedono quindi in file .class come una normale libreria di classi. Le interfacce sono diverse dalle classi a livello di dichiarazione, ecco la sintassi:
interface NomeInterfaccia [extends AltraInterfaccia1, AltraInterfaccia2, …]
{
… corpo dell’interfaccia …
}
Come si nota, le interfacce a differenza delle classi supportano l’ereditarietà multipla. A livello semantico le classi e le interfacce sono molto differenti, difatti occorre tenere bene a mente i seguenti punti fondamentali:
- Il corpo dell’interfaccia può accogliere solo variabili e dichiarazioni di metodi, non dovrà essere presente il corpo di nessun metodo dichiarato
- Data la generica interfaccia I, i suoi metodi potranno essere definiti in una qualsiasi classe C a patto che essa sia stata dichiarata nella maniera seguente: class C [extends superclasse] implements I. Per la precisione, ogni metodo di I dovrà necessariamente essere presente in C, pena la comparsa di un errore di compilazione.
- Non si possono creare oggetti di tipo interfaccia, vale a dire che data l’interfaccia I non si potrà scrivere: I un_oggetto = new I() pena la comparsa di un errore di compilazione.
Vediamo un semplice esempio pratico sulle interfacce in Java:
// file CCerchio.java pckage corso; public class CCerchio { protected final double pi = 3.14159; protected double m_dRaggio; CCerchio() { m_dRaggio = 0.0; } CCerchio(double dRaggio) { m_dRaggio = dRaggio; } void SetRaggio(double dRaggio) { m_dRaggio = dRaggio; } double GetRaggio() { return m_dRaggio; } double GetDiametro() { return m_dRaggio * 2; } double GetCirconferenza() { return 2 * pi * m_dRaggio; } double GetArea() { return m_dRaggio * m_dRaggio * pi; } } // File IDivisibile.java package corso; public interface IDivisibile { public void Dividi(double dValue); } // File CSfera.java package corso; public class CSfera extends CCerchio implements IDivisibile { CSfera(double dRaggio) { super(dRaggio); } public double GetSuperficie() { return GetCirconferenza() * 2.0 * GetRaggio(); } public double GetVolume() { return (GetArea() * 4.0 * GetRaggio()) / 3.0; } public void Dividi(double dValue) { m_dRaggio /= dValue; } } // file Main.java package corso; public class Main { public static void main(String[] args) { CSfera s = new CSfera(12.78); System.out.println("Il volume della sfera di raggio " + s.GetRaggio() + " è di " + s.GetVolume()); s.Dividi(2.0); System.out.println("Il volume della sfera di raggio " + s.GetRaggio() + " è di " + s.GetVolume()); } }
Nel JDK esistono varie Interfacce già pronte per l’uso come Cloneable, Runneable per la gestione dei thread ed inoltre DatInput, DataOutput e FilenameFilter e molte altre che scopriremo man mano che avanzeremo nel corso.
<< Lezione Precedente – Inizio Corso – Lezione Successiva >>