Menu


Trascrizione diapositive

1. Caratteristiche avanzate del linguaggio

  • Complessità: BASSA.


2. Breve riepilogo sui costruttori

  • Nella seconda unità sono stati introdotti in maniera approssimativa i metodi costruttori, di seguito un breve riepilogo delle proprietà che avevamo accennato:

    - Hanno lo stesso nome della classe cui appartengono.
    - Non hanno tipo di ritorno.
    - Sono chiamati solamente al momento che viene istanziato un oggetto della classe cui appartengono, relativamente a quell’oggetto.
    - Sono presenti in ogni classe.


3. Esempio senza costruttore

  • Di seguito, un esempio di classe java senza alcun metodo costruttore (notare la sequenza di istruzioni nel metodo main()):

[Download]

class Dipendente {
private String nome;
private int punteggio;
public void setNome(String n) {
this.nome = n;
}
public String getNome() {
return this.nome;
}
public void setPunteggio(int p) {
this.punteggio = p;
}
public int getPunteggio() {
return this.punteggio;
}

}

Si invoca così...

[Download]

public class Programma {
public static void main(String[] args) {
Dipendente fabrizio = new Dipendente();
Dipendente fabio = new Dipendente();
fabrizio.setNome("Fabrizio");
fabio.setNome("Fabio");
fabrizio.setPunteggio(7);
fabio.setPunteggio(6);
}
}

In verità, nell’esempio presentato esiste un metodo costruttore e si chiama costruttore di default, che viene definito in fase di compilazione da javac.


4. Esempio con costruttore

  • Di seguito, un altro analogo esempio dopo aver definito un metodo costruttore (notare la breve sintassi nel nuovo metodo main()):

[Download]

class Dipendente {
private String nome;
private int punteggio;
public Dipendente(String n, int p) {
this.setNome(n);
this.setPunteggio(p);
}
public void setNome(String n) {
this.nome = n;
}
public String getNome() {
return this.nome;
}
public void setPunteggio(int p) {
this.punteggio = p;
}
public int getPunteggio() {
return this.punteggio;
}
}

Si invoca così...

[Download]

public class Programma {
public static void main(String [] args) {
Dipendente fabrizio = new Dipendente(“Fabrizio”, 7);
Dipendente fabio = new Dipendente(“Fabio”, 6);
}
}

Bisogna constatare che il costruttore ha lo stesso nome della classe e che NON è stato dichiarato alcun tipo di ritorno.
Nell’esempio mostrato notiamo, inoltre, che il metodo costruttore è stato scritto dal programmatore, questo implica la scomparsa del costruttore di default.



5. Overload dei costruttori

  • Possiamo definire il costruttore come un metodo speciale, in quanto si tratta di definire una particolare azione che verrà eseguita al momento che viene istanziato un oggetto.
  • Dovrebbe essere oramai chiaro che; proprio come un semplice metodo, possiamo effettuare anche un overload del costruttore.
  • Nell’esempio precedente abbiamo rilevato che il compilatore non ha inserito il costruttore di default, questo perché avevamo inserito un costruttore in maniera esplicita, quindi ogni volta che avevamo l’intenzione di istanziare un oggetto, dovevamo passare dei parametri ben precisi al costruttore.
  • Grazie all’overload possiamo dichiarare un metodo costruttore senza alcun parametro affiancandolo ad un costruttore che accetta parametri, in modo tale da poter istanziare oggetti in modo diverso, possiamo anche aggiungere un qualsiasi altro tipo di costruttore in relazione alle nostre esigenze.


6. Overload dei costruttori

  • Ecco un esempio di overload del costruttore:

[Download]

class Dipendente {
private String nome;
private int punteggio;
public Dipendente(String n, int p) {
this.setNome(n);
this.setPunteggio(p);
}
public Dipendente() {}
public void setNome(String n) {
this.nome = n;
}
public String getNome() {
return this.nome;
}
public void setPunteggio(int p) {
this.punteggio = p;
}
public int getPunteggio() {
return this.punteggio;
}
}

Si invoca così...

[Download]

public class Programma {
public static void main(String [] args) {
Dipendente fabrizio = new Dipendente("Fabrizio“, 7);
Dipendente fabio = new Dipendente();
fabio.setNome("Fabio");
fabio.setPunteggio(6);
}
}

Nell’esempio mostrato notiamo che nella classe è stato utilizzato l’overload dei costruttori, inoltre, nel metodo main() sono stati istanziati due oggetti che eseguono rispettivamente un singolo costruttore diverso.


7. Override dei costruttori

  • C’è una differenza importante tra il costruttore ed il metodo:

  • - Il costruttore non è ereditato dalle «classi derivate».

  • Se il costruttore fosse ereditato dalle sottoclassi, non potrebbe essere invocato, giacché se istanziassimo un oggetto a partire da una sottoclasse, verrebbe invocato il metodo costruttore presente nella sottoclasse.
  • Di conseguenza non si può parlare di override di costruttori.


8. Nota sul costruttore

  • Bisogna precisare che per rispettare la regola dell’astrazione:

  • - Un qualsiasi costruttore (anche quello di default) come prima istruzione, deve invocare sempre il costruttore della sua superclasse.

  • Ad esempio la classe «Collaudatore»:

[Download]

class Dipendente {
public Dipendente() {
System.out.println("Sono un dipendente");
}
}
class Collaudatore extends Dipendente {
public Collaudatore() {
System.out.println("... e faccio il collaudatore");
}
}

Si invoca così...

[Download]

public class Programma {
public static void main(String[] args) {
Collaudatore fabio = new Collaudatore();
}
}

  • Restituirà il seguente output sullo schermo:

  • Sono un dipendente
    ... e faccio il collaudatore

  • e non...

  • ... e faccio il collaudatore


9. Il reference super

  • Tramite il reference super è possibile usufruire dei seguenti vantaggi:

  • - È possibile accedere dalla sottoclasse, ai membri pubblici della superclasse che sono stati riscrittioverride») e che quindi sono inaccessibili con il reference this.
  • - È possibile accedere ai costruttori della superclasse.

  • Deve essere considerato opportuno utilizzare il reference super ogni volta che da una sottoclasse, intendiamo fare riferimento esplicito ad un membro pubblico presente nella superclasse.


10. Il reference super

  • Ecco un esempio completo che fa uso del reference super:

[Download]

(Prima parte del codice)

class Dipendente {
private String nome;
private int oreLavorativeMensili;
private int retribuzioneOraria;
public void setNome(String nome) {
this.nome = nome;
}
public String getNome() {
return nome;
}
public void setOreLavorativeMensili(int oreLavorativeMensili) {
this.oreLavorativeMensili = oreLavorativeMensili;
}
public int getOreLavorativeMensili() {
return oreLavorativeMensili;
}
public void setRetribuzioneOraria(int retribuzioneOraria) {
this.retribuzioneOraria = retribuzioneOraria;
}
public int getRetribuzioneOraria() {
return retribuzioneOraria;
}
public int stipendio() {
return oreLavorativeMensili * retribuzioneOraria;
}
}


11. Il reference super

  • Ecco un esempio completo che fa uso del reference super:

[Download]

(Seconda parte del codice)

class ResponsabileProgetto extends Dipendente {
private int bonus;
public void setBonus(int bonus) {
this.bonus = bonus;
}

public int getBonus() {
return bonus;
}

@Override
public int stipendio() {
int stipendioFisso=(super.stipendio());

return stipendioFisso + bonus;
}
}

Si invoca così...

[Download]

  • public class Programma {
    public static void main(String [] args) {
    Dipendente giacomo = new Dipendente();
    giacomo.setNome("Giacomo");
    giacomo.setOreLavorativeMensili (150);
    giacomo.setRetribuzioneOraria(10);

    System.out.println (giacomo.stipendio());

    ResponsabileProgetto luigi = new ResponsabileProgetto();
    luigi.
    setNome("Luigi");
    luigi.
    setOreLavorativeMensili(150);
    luigi.
    setRetribuzioneOraria(10);
    luigi.setBonus(1000);

    System.out.println (luigi.stipendio());
    }
    }


12. Il reference super

  • Rileviamo che il reference super della precedente slide è stato utilizzato per richiamare il metodo «stipendio()» della superclasse.
  • Proprio per l’esistenza del reference super, quando si è parlato di «override» si è fatto sempre riferimento alla riscrittura piuttosto che alla sovrascrittura (traduzione letterale).
  • Anche se può inizialmente suonare strano, il reference super è da considerarsi una parola chiave del linguaggio perfettamente in linea con i paradigmi della programmazione ad oggetti, infatti se un «ResponsabileProgetto» è anche un «Dipendente» (ereditarietà), possiamo affermare che deve poter eseguire tutto quello che può eseguire un «Dipendente».


13. Il reference super e i costruttori

  • Abbiamo notato in una precedente slide che il costruttore (anche quello di default), come prima istruzione, invoca sempre il costruttore della sua superclasse.
  • Bisogna adesso comprendere che questo fenomeno accade perché in ogni classe è sempre presente una chiamata al metodo costruttore della superclasse, che avviene tramite il reference super.
  • Dovremo essere oramai a conoscenza che il compilatore aggiunge automaticamente del codice in fase di compilazione, quindi è facile immaginare che quando scriviamo del codice sorgente e omettiamo di inserire come prima istruzione il reference super all’interno di un metodo costruttore, esso verrà inserito automaticamente da javac.


14. Il reference super e i costruttori

  • Ad esempio la seguente classe:

[Download]

class Dipendente {
public Dipendente() {
System.out.println ("Sono un dipendente ");
}
}

class Collaudatore extends Dipendente {
public Collaudatore() {
System.out.println ("...e faccio il collaudatore");
}
}

Si invoca così...

[Download]

public class Programma {
public static void main(String [] args) {
Collaudatore fabio = new Collaudatore();
}
}

  • Restituisce il seguente output sullo schermo:

Sono un dipendente
...e faccio il collaudatore

  • Perché viene riscritta dal compilatore javac in questo modo:

class Dipendente {
public Dipendente() {
super();
System.out.println ("Sono un dipendente ");
}
}

class Collaudatore extends Dipendente {
public Collaudatore() {
super();
System.out.println ("...e faccio il collaudatore");
}
}

Si invoca così...

  • public class Programma {
    public static void main(String [] args) {
    Collaudatore fabio = new Collaudatore();
    }
    }


15. Il reference super e i costruttori

  • Se avessimo inserito manualmente l’istruzione «super()», con o senza parametri, il compilatore non avrebbe aggiunto alcunché.
  • La chiamata al costruttore della superclasse mediante il reference super, deve essere la prima istruzione di un costruttore, inoltre, questa istruzione potrà essere inserita solo all’interno di un metodo costruttore.


16. Il reference this e i costruttori

  • Se con il reference super dobbiamo chiamare il costruttore della superclasse, con il reference this possiamo chiamare un costruttore presente nella stessa classe. Ecco un esempio:

[Download]

class Persona {
private String nome;
private String cognome;
public Persona(String n) {
this.setNome(n);
}
public Persona(String n, String c) {
this(n);
this.setCognome(c);
}
public void setNome(String n) {
this.nome = n;
}
public String getNome() {
return this.nome;
}
public void setCognome(String c) {
this.cognome = c;
}
public String getCognome() {
return this.cognome;
}
}

Si invoca così...

[Download]

public class Programma {
public static void main(String [] args) {
Persona fabrizio = new Persona("Fabrizio");
Persona fabio = new Persona("Fabio", "Rossi");
fabrizio.setCognome("Bianchi");
System.out.println (fabrizio.getNome()+" "+fabrizio.getCognome());
System.out.println (fabio.getNome()+" "+fabio.getCognome());
}
}

La chiamata ad un diverso costruttore tramite il reference «this()», non inibisce il compilatore per quanto riguarda l’aggiunta automatica dell’istruzione «super()», che in questo caso invoca il metodo costruttore della classe Object (non provocherà nessun risultato visibile agli occhi dello sviluppatore).