Unità didattica 8.1) - Pagina 1
Unità didattica 8.2) - Pagina 2
Unità didattica 8.3) - Pagina 3
Unità didattica 8.4) - Pagina 4
3 - Unità didattica 8.3)
- super: un "super-reference"
Nel modulo 5, abbiamo definito la parola chiave
this, come "reference implicito all’oggetto corrente". Possiamo
definire la parola chiave super, come "reference implicito
all’intersezione tra l’oggetto corrente e la sua superclasse".
Ricordiamo per l’ennesima volta, che l’ereditarietà tra due classi
si applica solo dopo aver utilizzato la relazione "is a".
Consideriamo nuovamente le classi Punto e Punto3D del modulo
precedente. Tramite il reference super, un oggetto della classe
Punto3D potrà, non solo accedere ai membri della superclasse Punto
che sono stati riscritti, ma addirittura ai costruttori della
superclasse! Ciò significa che da un metodo della classe Punto3D si
potrebbe invocare il metodo dammiDistanza della superclasse Punto,
mediante la sintassi:
super.dammiDistanza(p); // chiamata al metodo
//della superclasse riscritto nella sottoclasse.
//Il reference p è di tipo Punto
N.B.: ciò è possibile, ma nell’esempio specifico improduttivo.
L’esistenza del reference super, quale parola chiave del linguaggio,
è assolutamente in linea con i paradigmi dell’object orientation.
Infatti, se un punto tridimensionale è anche un punto
(ereditarietà), deve poter eseguire tutto ciò che può eseguire un
punto. L’inefficacia dell’utilizzo di super nell’esempio presentato,
è ancora una volta da imputare alla violazione dell’astrazione della
classe Punto. Per esempio consideriamo il seguente codice che si
avvale di un’astrazione corretta dei dati:
public class Persona
{
private String nome, cognome;
public String toString()
{
return nome + " " + cognome;
}
. . .
//metodi di accesso (set e get)
}
public class Cliente extends Persona
{
private String indirizzo, telefono;
public String toString()
{
return super.toString()+ "\n"+
indirizzo + "\nTel:" + ;
}
. . .
//metodi di accesso (set e get)
}
- super e i costruttori
La parola chiave super, è strettamente legata al concetto di
costruttore. In ogni costruttore, infatti, è sempre presente una
chiamata al costruttore della superclasse, tramite una sintassi
speciale, che sfrutta il reference super.
Andiamo a riscrivere nuovamente le revisioni effettuate nel
precedente paragrafo alle classi Punto e Punto3D, dove avevamo
introdotto due costruttori senza parametri che stampano messaggi:
public class Punto
{
private int x, y;
public Punto()
{
System.out.println("Costruito punto
bidimensionale");
}
. . .
}
class Punto3D extends Punto
{
private int z;
public Punto3D()
{
System.out.println("Costruito punto
tridimensionale");
}
. . .
}
Precedentemente, avevamo anche notato che un
costruttore non può essere ereditato da una sottoclasse. Eppure, l’ouput
della seguente istruzione, in cui istanziamo un Punto3D:
new Punto3D();
sarà:
Costruito punto bidimensionale
Costruito punto tridimensionale
Questo sorprendente risultato, non implica che il costruttore della
superclasse sia stato ereditato, ma solamente che sia stato
chiamato. Infatti, tramite l’istruzione super(), che il compilatore
ha inserito al momento della compilazione, alla prima riga del
costruttore della superclasse, è stato invocato il costruttore della
classe Punto. La chiamata ad un costruttore della superclasse è
inevitabile! L’unico modo in cui possiamo evitare che il compilatore
introduca un’istruzione super() nei vari costruttori, è introdurre
esplicitamente un comando di tipo super(). Per esempio potremmo
sfruttare al meglio la situazione modificando le due classi in
questione nel seguente modo:
public class Punto
{
private int x, y;
public Punto()
{
super(); //inserito dal compilatore
}
public Punto(int x, int y)
{
uper(); //inserito dal compilatore
setX(x); //riuso del codice già scritto
setY(y);
}
. . .
}
class Punto3D extends Punto
{
private int z;
public Punto3D()
{
super(); //inserito dal compilatore
}
public Punto3D(int x, int y, int z)
{
super(x,y); //Chiamata esplicita al
//costruttore con due parametri interi
setZ(z);
}
. . .
}
In questo modo, l’unica istruzione di tipo
super(x,y) inserita esplicitamente, darà luogo ad un risultato
constatabile: il settaggio delle variabili ereditate, tramite
costruttore della superclasse.
N.B.: la chiamata al costruttore della superclasse mediante super
deve essere la prima istruzione di un costruttore, e, ovviamente,
non potrà essere inserita all’interno di un metodo che non sia un
costruttore.
N.B.: il rapporto tra super e i costruttori può essere considerato
una manifestazione emblematica del fatto che Java obbliga lo
sviluppatore a programmare ad oggetti.
N.B.: il lettore potrà notare la somiglianza tra il reference super
e il reference this. Se tramite super abbiamo la possibilità (anzi
l’obbligo) di chiamare un costruttore della superclasse, tramite
this da un costruttore potremo invocare un altro costruttore della
stessa classe. Presentiamo un esempio:
public class Persona
{
private String nome, cognome;
public Persona(String nome)
{
super();
this.setNome(nome);
}
public Persona(String nome, String cognome)
{
this(nome); //chiamata al costruttore precedente
this.setCognome(cognome);
}
. . .
//metodi di accesso (set e get)
}
N.B.: la chiamata al costruttore della superclasse mediante this
deve essere la prima istruzione di un costruttore, e, ovviamente,
non potrà essere inserita all’interno di un metodo che non sia un
costruttore.
N.B.: la chiamata ad un altro costruttore della stessa classe
mediante this rimanda solamente la chiamata al costruttore della
superclasse. Infatti, questa viene effettuata all’interno del
costruttore chiamato.
N.B.: ogni costruttore di ogni classe, una volta chiamato,
direttamente o indirettamente andrà ad invocare il costruttore della
classe Object, che non provocherà nessun risultato visibile agli
occhi dello sviluppatore...
Unità didattica 8.1) - Pagina 1
Unità didattica 8.2) - Pagina 2
Unità didattica 8.3) - Pagina 3
Unità didattica 8.4) - Pagina 4