a cura di Dario Dariol
 
    Soluzione Esercizio 005 - Ancora costanti

    L'esercizio riguardava ancora (è l'ultima volta, lo prometto!) l'uso del modificatore final in Java. Rivediamo e commentiamo l'esercizio.
     

      La seguente classe dichiara una costante s inizializzata al valore ritornato dal metodo f (che ritorna il valore della costante t) e una costante t inizializzata a 5. Quindi s e t valgono entrambi 5.

      class JavaQuiz5 {
        final int s = f();
        final int t = 5;
        int f() {
          return t;
        }

      Quindi vengono dichiarate delle variabili ss e tt e un metodo ff simili ai precedenti ma senza l'uso del modificatore final.

        int ss = ff();
        int tt = 5;
        int ff() {
          return tt;
        }

      I valori di ss e tt saranno eguali ai valori di s e t oppure il modificatore final avrà influito in qualche modo? Verifichiamolo con il resto dell'esempio: 

        JavaQuiz5(){
          System.out.println("s="+s  +" ss="+ss+
                            " f="+f()+" ff="+ff());
        }

        public static void main(String[]args) {
          new JavaQuiz5();
        }
      }

      che compilato ed eseguito stampa: 

         prompt> javac JavaQuiz5.java
         prompt> java JavaQuiz5
         s=5 ss=0 f=5 ff=5
         prompt>


    Ecco qui la sorpresa: s, fe ff sono effettivamente tutti eguali a 5, mentre ss vale zero. Ma s e ss non dovrebbero avere lo stesso valore? E quale è il valore corretto: 0 o 5?

    La risposta a queste due domande è complessa e dubbia. Vediamo di capire il perché.

    Se ci riferiamo alla specifica ufficiale di Java allora effettivamente s e ss dovrebbero avere lo stesso valore ed essere entrambi eguali a 0 perche' la sezione 12.5 della specifica dice chiaramente al punto 4 che:

      Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class.
    La frase evidenziata in neretto implica che s e t (e anche ss e tt) sono inizializzati nell'ordine dato (prima s e poi t e quindi anche prima ss e poi tt) e quindi quando viene invocata la funzione f(oppure la ff) per inizializzare s ( o ss), t (e anche tt) vale ancora 0, perché t (e anche tt) sarà inizializzato a 5 solo dopo l'inizializzazione di s (e anche ss). Quindi secondo la specifica di Java la risposta corretta dell'esercizio sarebbe:
      s=0 ss=0 f=5 ff=5


    Ma allora perché il nostro interprete Java stampa invece la seguente riga?

      s=5 ss=0 f=5 ff=5


    E' un bug del nostro interprete? No. Tutti gli interpreti Java stampano la stessa cosa. Il vero problema è che la specifica Java è scorretta! Può sembrare strano ma è così. La specifica Java è semplicemente un documento e come tale può avere degli errori (refusi) o delle omissioni (non essere completo e non contemplare tutti i casi possibili).

    In questo esempio, in particolare, la specifica omette di dire che come con i static fields durante l'inizializzazione delle classi, anche i final instance fields che sono inizializzati a constant expressions sono inizializzati prima degli altri instance fields. Così il precedente punto 4 della sezione 12.5 della specifica dovrebbe recitare:

      Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable initializers to the corresponding instance variables, in the left-to-right order in which they appear textually in the source code for the class, except that final instance variables whose values are compile-time constants are initialized first.
    Con questa nuova e corretta specifica allora t, che possiede un inizializzatore con la constant-expression 5, è inizializzato prima di s che possiede un inizializzatore con una espressione non costante f(). E quindi dapprima 5 è assegnato a t e poi per s si valuta la f() che ritorna 5.

    Questo particolare errore nella specifica di Java è descritto in questa pagina di Java Spec Report. Java Spec Report è un sito che raccoglie, in maniera non ufficiale, gli errata per le specifiche di Java. Pur non essendo un sito ufficiale della Sun Microsystems la sua autorevolezza è grande e tutti i realizzatori di compilatori e interpreti Java vi fanno costante riferimento.

    Attualmente Java Spec Report raccoglie quasi un centinaio (97 per la precisione) errata riguardanti le specifiche di Java.

 




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