a cura di Dario Dariol
 
    Soluzione Esercizio 008 - Subclassing

    Facendo riferimento a questo semplice programma:

      class Super {
        int what = 1;
        void printThis() { System.out.print(what); }
        Super() { printThis(); }
      }

      class Under extends Super {
        int what = 3;
        void printThis() { System.out.print(what); }
        Under() { printThis(); }
      }

      class Quiz8 {
        public static void main(String[] args) {
          new Super();
          new Under();
        }
      }

    avevo provocatoriamente chiesto: 

    Prima domanda

  • E' solo una complicata maniera di stampare 113? 
    Era, ovviamente (!), una provocazione...
    Questo programma non stampa 113 (d'altronde tra i commenti HTML lo avevo anche chiaramente affermato... ma chi legge mai i commenti di un sorgente HTML?).
    Ma allora, cosa stampa?
    E' abbastanza semplice poter affermare che: 
  • il costruttore di un oggetto Super stampa all'inizio 1 
  • il costruttore di un oggetto Under stampa alla fine 3 
    Quindi possiamo intanto dire che la prima e ultima cifra stampate da questo programma sono 1 e 3. E la cifra di mezzo? L'unico punto dubbio è infatti legato al costruttore di Super quando esso sia implicitamente invocato dal costruttore di Under

    Riassumiamo le regole di Java (sezione 12.5 della specifica) legate alla invocazione di:

    new Under()

1. E' allocato spazio per Under e tutte le sue superclassi, quindi in particolare è allocato spazio per il campo what di Under e per il campo what di Super

2. Tutti i campi di Under e tutti quelli delle sue superclassi sono inizializzati al loro valore default, quindi in particolare what di Under e what di Super sono entrambi inizializzati a zero; 

3. E' automaticamente invocato il costruttore di Super come prima istruzione del costruttore di Under. Infatti il costruttore di Under

{ printThis(); }

equivale a: 

{ super(); printThis(); }

4. Sono eseguiti gli inizializzatori dei campi di Super, quindi what di Super è inizializzato a 1; 

5. E' invocato il costruttore di Super che, dopo aver automaticamente invocato il costruttore di Object, invoca lo statement 

printThis();

6. Il metodo printThis presente in Super è presente anche in Under con la stessa signature (printThis è overrided in Under) e poiché qui stiamo effettivamente costruendo un oggetto Under (stiamo infatti vedendo cosa succede quando si invoca new Under()) viene allora invocato il metodo printThis di Under;

7. Il metodo printThis di Under stampa il valore what di Under che a questo punto vale ancora zero (perché è stato inizializzato a zero al punto 2 e non è stato ancora eseguita la sua inizializzazione a 3). Quindi viene stampato zero! 

8. Terminato il costruttore di Super (cominciata al punto 3) sono eseguite le inizializzazioni dei campi di Under, quindi what di Under viene inizializzato a 3 solo adesso! 

9. Prosegue il costruttore di Under con la chiamata printThis che stampa il valore what di Under che a questo punto vale 3.

    Riassumendo il programmino di esempio stampa 103 e non 113 !

    Chiaro? Se le cose sono ancora un po' oscure fate un salto qui. Se invece tutto vi è chiaro, possiamo passare alla

    Seconda domanda

  • Cosa cambia se nelle due dichiarazioni di what si aggiunge un final?
    La prima ovvia banale risposta potrebbe essere: nulla, stampa sempre 103! 

    No, le cose non stanno così. Lo abbiamo già visto nella soluzione del quiz 5 del settembre dello scorso anno. Anche se allora avevo promesso di non parlare più dell'uso del modificatore final in Java, eccomi qui di nuovo!

      La cosa è molto sottile e molto importante e di solito si tende a dimenticarsi di cosa voglia dire usare final. Si pensa a final solo per dichiarare delle costanti, ma ci si dimentica quando queste costanti siano inizializzate.
    Ebbene in questo caso i campi final inizializzati con espressioni valutabili a tempo di compilazione (come ad esempio le semplici espressioni 1 o 3) sono inizializzati subito dopo il precedente passo 2 e quindi in un passo 2.bis cosi congegnato:

    2.bis Tutti i campi di Under e tutte le sue superclassi che hanno il modificatore final con espressioni valutabili a tempo di compilazione sono inizializzati a questi valori e quindi, nel caso particolare, what di Super è inizializzato a 1 e what di Under è inizializzato a 3.

    In questo modo il successivo passo 7 (chiamata di printThis in Under) trova what di Under che vale 3, e quindi il nostro programmino stampa quindi 133.

    Tutto chiaro!

    Spero che tutto sia stato abbastanza chiaro. Potete in ogni caso contattarmi via email per ulteriori chiarimenti e disquisizioni.

 




MokaByte®  è un marchio registrato da MokaByte s.r.l.

Java® è un marchio registrato da Sun Microsystems; tutti i diritti riservati

E' vietata la riproduzione anche parziale
Per comunicazioni inviare una mail a
mokainfo@mokabyte.it