Académique Documents
Professionnel Documents
Culture Documents
In Java presente solo unereditariet singola, cio una sottoclasse pu avere una sola superclasse. Per creare una sottoclasse si utilizza la parola chiave extends, secondo la seguente sintassi: class <nome classe> extends <nome superclasse> Per il resto, la sottoclasse mantiene la struttura di una classe normale.
e la sua implementazione in Java, in base alle seguenti supposizioni: 1. la variabile di istanza numB pubblica; 2. i metodi setNum e getNum sono pubblici; 3. entrambe le classi hanno solo un costruttore di default; 4. la variabile di istanza numD privata (me se fosse pubblica non cambierebbe niente in questo esempio).
class ClasseBase { public int numB; public void setNum(int numB) { this.numB= numB; } public int getNum() { return numB; } } class ClasseDerivata extends ClasseBase { private int numD; } Creiamo una istanza di ClasseDerivata, che chiameremo d, utilizzando il costruttore di default: ClasseDerivata d = new ClasseDerivata(); Loggetto creato rappresentato in figura 2.
valore
numB = 10;
alla variabile di istanza numB in lettura, per esempio
valore
numD = 100;
int numero = numD; La variabile di istanza numB, definita all'interno di ClasseBase, si comporta a tutti gli effetti come se fosse una variabile dell'oggetto d, istanza di ClasseDerivata.
Sull'oggetto d inoltre possibile richiamare i metodi setNum e getNum, proprio come se fossero definiti all'interno di ClasseDerivata. Per esempio: d.setNum(5); assegna alla variabile di istanza numB dell'oggetto d il valore 5. int numero = d.getNum(); assegna alla variabile intera numero il valore dell'attributo numB dell'oggetto d. Supponiamo ora che la variabile di istanza numB non sia pubblica ma privata, come solitamente accade, e consideriamo nuovamente l'implementazione delle due classi. class ClasseBase { private int numB; public void setNum(int numB) { this.numB = numB; } public int getNum() { return numB; } } class ClasseDerivata extends ClasseBase { private int numD; } In questo caso, le modalit di accesso alla variabile di istanza numB sono diverse: i metodi definiti in ClasseDerivata non possono pi utilizzare numB come se si trattasse di una variabile di istanza della classe stessa, ma per accedere in lettura e scrittura devono utilizzare i metodi getNum e setNum:
l'accesso a numB in scrittura possibile solo nel seguente modo
this.setNum(10);
l'accesso a numB in lettura possibile solo nel seguente modo
Quando si crea un oggetto come istanza di una classe derivata, Java inserisce automaticamente la chiamata al costruttore della classe base, nel costruttore della classe derivata. Possiamo distinguere tre casi:
in precedenza; 2. nella classe base definito un costruttore senza parametri; riconducibile al caso 1;
Bocchi Cinzia Ultimo aggiornamento: 20/11/2012
dove lista di parametri contiene i parametri attuali, separati da virgola, da passare al metodo costruttore della classe base. Possiamo, a questo punto, riscrivere il codice nellesempio, tenendo conto di quanto stato detto class ClasseBase { private int numB; public ClasseBase(int numB) { this.numB = numB; } public void setNum(int numB) { this.numB = numB; } public int getNum() { return numB; } } class ClasseDerivata extends ClasseBase { private int numD; public ClasseDerivata(int numB) { super(numB); } } Attenzione! La chiamata esplicita al costruttore di una classe base deve essere inserita come prima istruzione allinterno del costruttore della classe derivata (prima ancora della dichiarazione di eventuali variabili locali). Supponendo che il valore del parametro num sia 10, la creazione delloggetto d determina la seguente situazione: ClasseDerivata d = new ClasseDerivata(10); delle due classi considerate
Se si desidera definire per la classe derivata un costruttore che si occupi di inizializzare anche la variabile di istanza numD, si pu aggiungere: public ClasseDerivata(int numB, int numD) { super(numB); this.numD = numD; }
La creazione dell'oggetto d, avviene con la chiamata: ClasseDerivata d = new ClasseDerivata(10, 5); la quale crea un'istanza di ClasseDerivata, inizializzando numB al valore 10 e numD al valore 5, come si pu vedere nel seguente diagramma.
Esistono due modi per modificare linterfaccia (cio l'insieme dei metodi pubblici) della classe derivata.
1. Possiamo
definire nella sottoclasse, qualche metodo in pi, se occorre (estensione dei metodi); ad esempio aggiungiamo alla classe derivata il metodo che calcola e restituisce la somma di numB e di numD class ClasseDerivata extends ClasseBase { private int numD; public ClasseDerivata(int nb,int nd) { super(nb); numD= nd; } public int somma() { int s; int nb; nb= this.getNum(); s= numD+nb; return s; } }
//restituisce numB in nb
Attenzione! Il metodo somma pu essere richiamato su un qualsiasi oggetto della classe ClasseDerivata, ma non su un oggetto della classe ClasseBase. Per esempio, se b un'istanza di ClasseBase, la chiamata int somma= b.somma(); genera un errore in fase di compilazione, perch somma non un metodo di ClasseBase.
determiner la chiamata del metodo setNum della classe base o della classe derivata? Il problema non pu essere risolto in fase di compilazione ma a tempo di esecuzione con il binding dinamico: l'interprete individua il tipo (la classe) dell'oggetto sul quale viene chiamato il metodo;
in seguito ricerca nella classe e in tutte le sue superclassi i metodi non privati che hanno lo stesso nome; infine esclude tutti i metodi che hanno lo stesso nome ma numero o tipo di parametri diversi.
Se l'interprete individua pi metodi coincidenti in nome, numero e tipo di parametri, sceglie quello che si trova nella classe al livello pi basso della gerarchia di ereditariet. Nel caso dell'esempio, il compilatore sceglie il metodo setNum della classe derivata. Se il metodo chiamato private, static o final, il compilatore sa che pu utilizzare solo un metodo della classe di cui l'oggetto rappresenta un'istanza: in tal caso il problema viene risolto in fase di compilazione e si parla di binding statico. Nota: Vedremo pi avanti che il tipo di un oggetto non coincide necessariamente con il tipo della variabile che contiene il riferimento ad esso. Il tipo di un oggetto sempre e solo la classe di cui loggetto rappresenta unistanza.
Polimorfismo
Un oggetto della sottoclasse anche un oggetto della superclasse, ma non vale il viceversa. In altre parole, per creare unistanza di Classe Derivata possibile scrivere sia ClasseDerivata d = new ClasseDerivata (0,10); sia ClasseBase d = new ClasseDerivata (0,10); In entrambi i casi le istanze create sono dello stesso tipo, cio ClasseDerivata. Si dice che il tipo run time delloggetto d ClasseDerivata. Il tipo della variabile reference b invece diverso: ClasseDerivata nel primo caso, ClasseBase nel secondo. Questa caratteristica, tipica dei linguaggi a oggetti, prende il nome di polimorfismo (molte forme). Allatto dellinvocazione di un metodo su d, linterprete individuer il tipo run time (binding dinamico) e sar in grado di selezionare correttamente il metodo da eseguire. Tutto ci realizzabile grazie al principio di sostituzione di Liskov, in base al quale sempre possibile sostituire un oggetto della superclasse con un oggetto della sottoclasse. La seguente porzione di codice non viene invece accettata dal compilatore: ClasseDerivata d = new ClasseBase (0); Non mai possibile sostituire un oggetto della sottoclasse con un oggetto della superclasse.
Se non si vuole impedire l'estensione dell'intera classe ma solo di alcuni metodi, basta dichiararli final: in questo caso sar possibile derivare una sottoclasse dalla classe di base, ma i metodi final non saranno ereditati.
____________________________________________________________________
Quest'opera stata rilasciata con licenza Creative Commons Attribution-ShareAlike 3.0 Unported. Per leggere una copia della licenza visita il sito web http://creativecommons.org/licenses/by-sa/3.0/ o spedisci una lettera a Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
10