2013-05-31 22 views
79
class Test{ 
    public static void main(String arg[]){  
     System.out.println("**MAIN METHOD"); 
     System.out.println(Mno.VAL);//SOP(9090); 
     System.out.println(Mno.VAL+100);//SOP(9190); 
    } 

} 

class Mno{ 
    final static int VAL=9090; 
    static{ 
     System.out.println("**STATIC BLOCK OF Mno\t:"+VAL); 
    } 
} 

So che un blocco static viene eseguito quando la classe è stata caricata. Ma in questo caso la variabile di istanza all'interno della classe Mno è final, a causa di ciò il blocco static non è in esecuzione.Blocco statico in Java non eseguito

Perché è così? E se dovessi rimuovere lo final, funzionerebbe correttamente?

Quale memoria verrà allocata per prima, la variabile static final o il blocco static?

Se, a causa del modificatore di accesso final, la classe non viene caricata, come può la variabile recuperare la memoria?

+1

Qual è l'errore esatto e il messaggio che si ottiene? – Patashu

+0

@Patashu, non ci sono errori, è un dubbio – Sthita

risposta

125
  1. Un campo static final int è un fase di compilazione costante e il suo valore è codificata nella classe destinazione senza riferimento alla sua origine;
  2. pertanto la classe principale non attiva il caricamento della classe che contiene il campo;
  3. pertanto l'inizializzatore statico in quella classe non viene eseguito.

In dettaglio specifico, il bytecode compilato corrisponde a questo:

public static void main(String arg[]){  
    System.out.println("**MAIN METHOD"); 
    System.out.println(9090) 
    System.out.println(9190) 
} 

Non appena si rimuove final, esso non è più una fase di compilazione costante ed il comportamento speciale sopra descritto non si applica. La classe Mno viene caricata come previsto e viene eseguito il suo inizializzatore statico.

+1

Ma come si valuta il valore della variabile finale nella classe senza caricare la classe? –

+17

Tutte le valutazioni avvengono in fase di compilazione e il risultato finale è codificato in tutte le posizioni che fanno riferimento alla variabile. –

+1

Quindi, se al posto di una variabile primitiva, si tratta di un oggetto, quindi tale codifica non sarà possibile. Non è vero? Quindi, in quel caso, la classe verrà caricata e il blocco statico verrà eseguito? –

0

Per quanto ne so, verrà eseguito in ordine di apparizione. Per esempio:

public class Statique { 
    public static final String value1 = init1(); 

    static { 
     System.out.println("trace middle"); 
    } 
    public static final String value2 = init2(); 


    public static String init1() { 
     System.out.println("trace init1"); 
     return "1"; 
    } 
    public static String init2() { 
     System.out.println("trace init2"); 
     return "2"; 
    } 
} 

stamperà

trace init1 
    trace middle 
    trace init2 

ho appena provato e la statica vengono inizializzati (=> stampa) quando la classe "statique" viene effettivamente utilizzato e "giustiziato" in un altro pezzo di codice (il mio caso ho fatto "nuova statique()".

+2

Stai ottenendo questo output perché stai caricando la classe 'Statique' facendo' new Statique() '. Mentre nella domanda posta, la classe 'Mno' non è affatto caricata. – RAS

+0

@RAS hai assolutamente ragione ... Mno non è caricato. – Sthita

+0

@Fabyen, se sto creando l'oggetto di Mno in una classe di test come questa: Mno anc = New Mno(); quindi il suo fine, ma lo scenario attuale non lo sto facendo, il mio dubbio è che se sto rimuovendo il finale allora il blocco statico viene eseguito altrimenti non viene eseguito, perché così ?? – Sthita

7

il motivo per cui la classe non è caricata è che VAL è finale viene inizializzato con a constant expression (9090). Se, e solo se, queste due condizioni sono soddisfatte, la costante viene valutata in fase di compilazione e "hardcoded" dove necessario.

Per evitare che l'espressione venga valutata al momento della compilazione (e per rendere la JVM caricare la classe), è possibile:

  • rimuovere la parola finale:

    static int VAL = 9090; //not a constant variable any more 
    
  • o cambia l'espressione del lato destro a qualcosa di non costante (anche se la variabile è ancora finale):

    final static int VAL = getInt(); //not a constant expression any more 
    static int getInt() { return 9090; } 
    
5

Se vedete generato bytecode usando javap -v Test.class, main() viene fuori come:

public static void main(java.lang.String[]) throws java.lang.Exception; 
    flags: ACC_PUBLIC, ACC_STATIC 
    Code: 
     stack=2, locals=1, args_size=1 
     0: getstatic  #2     // Field java/lang/System.out:Ljava/io/PrintStream; 
     3: ldc   #3     // String **MAIN METHOD 
     5: invokevirtual #4     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
     8: getstatic  #2     // Field java/lang/System.out:Ljava/io/PrintStream; 
     11: sipush  9090 
     14: invokevirtual #5     // Method java/io/PrintStream.println:(I)V 
     17: getstatic  #2     // Field java/lang/System.out:Ljava/io/PrintStream; 
     20: sipush  9190 
     23: invokevirtual #5     // Method java/io/PrintStream.println:(I)V 
     26: return   

Si può chiaramente vedere nella "11: sipush 9090" che il valore finale statico viene utilizzato direttamente, perché Mno.VAL è un momento della compilazione costante. Pertanto non è necessario caricare la classe Mno. Quindi il blocco statico di Mno non viene eseguito.

È possibile eseguire il blocco statico caricando manualmente Mno come qui sotto:

class Test{ 
    public static void main(String arg[]) throws Exception { 
     System.out.println("**MAIN METHOD"); 
     Class.forName("Mno");     // Load Mno 
     System.out.println(Mno.VAL); 
     System.out.println(Mno.VAL+100); 
    } 

} 

class Mno{ 
    final static int VAL=9090; 
    static{ 
     System.out.println("**STATIC BLOCK OF Mno\t:"+VAL); 
    } 
} 
1

1) In realtà non si dispone estende quella classe Mno così quando compilazione avviarlo genererà costante variabile VAL e quando inizia l'esecuzione quando questa variabile è necessaria per il suo carico dalla memoria. Quindi non è necessario il riferimento alla classe in modo che non venga eseguita la static bock.

2) se una classe estende quella classe Mno in quel momento che il blocco statico è incluso nella classe A se si esegue questa operazione, viene eseguito quel blocco statico. per esempio .. public class A estende Mno {

public static void main(String arg[]){  
    System.out.println("**MAIN METHOD"); 
    System.out.println(Mno.VAL);//SOP(9090); 
    System.out.println(Mno.VAL+100);//SOP(9190); 
} 

} 

class Mno{ 
     final static int VAL=9090; 
    static`{` 
     System.out.println("**STATIC BLOCK OF Mno\t:"+VAL); 
    } 
} 
Problemi correlati