2013-05-31 4 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); 
    } 
} 

Ich weiß, dass ein static Block ausgeführt, wenn Klasse geladen. Aber in diesem Fall ist die Instanzvariable innerhalb der Klasse Mnofinal, deshalb wird der static Block nicht ausgeführt.Statischer Block in Java nicht ausgeführt

Warum ist das so? Und wenn ich die final entfernen würde, würde es gut funktionieren?

Welcher Speicher wird zuerst zugewiesen, die static final Variable oder der static Block?

Wenn aufgrund des Zugriffsmodifizierers final die Klasse nicht geladen wird, wie kann dann die Variable Speicher abrufen?

+1

Was ist die genauen Fehler und Nachricht, die Sie bekommen? – Patashu

+0

@Patashu, es gibt keinen Fehler, es ist ein Zweifel – Sthita

Antwort

125
  1. A static final int Feld ist ein Kompilierung Zeitkonstante und sein Wert wird ohne Bezugnahme auf seine Herkunft in die Zielklasse fest einprogrammiert;
  2. daher löst Ihre Hauptklasse nicht das Laden der Klasse aus, die das Feld enthält;
  3. daher der statische Initialisierer in dieser Klasse nicht ausgeführt wird.

In beschreiben, entspricht die kompilierte Bytecode dazu:

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

Sobald Sie final entfernen, ist es nicht mehr eine Kompilierung-Konstante und die spezielle oben beschriebene Verhalten gilt nicht. Die Mno-Klasse wird wie erwartet geladen, und ihr statischer Initializer wird ausgeführt.

+1

Aber wie wird dann der Wert der letzten Variablen in der Klasse ausgewertet, ohne die Klasse zu laden? –

+17

Die gesamte Auswertung erfolgt zur Kompilierzeit und das Endergebnis ist in alle Stellen festgeschrieben, die auf die Variable verweisen. –

+1

Wenn also anstelle einer primitiven Variablen ein Objekt vorhanden ist, ist eine solche Hardcodierung nicht möglich. Ist es nicht? Also, in diesem Fall, wird diese Klasse geladen und der statische Block wird ausgeführt? –

0

Soweit ich weiß, wird es in der Reihenfolge ihres Auftretens ausgeführt. Zum Beispiel:

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"; 
    } 
} 

drucken

trace init1 
    trace middle 
    trace init2 

ich es getestet und die Statik initialisiert (=> Druck), wenn die Klasse „Statique“ tatsächlich verwendet wird und „ausgeführt“ in einem anderen Stück Code (mein Fall I „neuen Statique()“ habe.

+2

Sie erhalten diese Ausgabe, weil Sie die 'Statique' Klasse mit 'new Statique()' laden. Während in der Frage gefragt wird, ist "Mno" -Klasse überhaupt nicht geladen. – RAS

+0

@RAS ist absolut richtig ... Mno ist nicht geladen. – Sthita

+0

@Fabyen, wenn ich ein Objekt von Mno in der Testklasse wie folgt erstelle: Mno anc = New Mno(); dann ist es in Ordnung, aber das aktuelle Szenario Ich mache das nicht, mein Zweifel ist, wenn ich endgültig entfernen dann der statische Block führt gut aus sonst wird es nicht ausgeführt, warum so ?? – Sthita

7

der Grund, warum die Klasse nicht geladen wird, ist, dass VAL ist finaluND es mit a constant expression (9090). wenn, und nur initialisiert wird, wenn, Diese beiden Bedingungen werden erfüllt, die Konstante wird zum Zeitpunkt der Kompilierung ausgewertet und, wo erforderlich, "fest codiert".

Um die Expression zu verhindern, bei der Kompilierung ausgewertet wird (und die JVM laden Sie Ihre Klasse zu machen), können Sie entweder:

  • das letzte Stichwort entfernen:

    static int VAL = 9090; //not a constant variable any more 
    
  • oder Ändere den Ausdruck der rechten Seite in etwas, das nicht konstant ist (selbst wenn die Variable immer noch endgültig ist):

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

Wenn Sie Bytecode mit javap -v Test.class erzeugt zu sehen, main() kommt wie:

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   

Sie können eindeutig in „11: sipush 9090“, dass statische Endwert sehen direkt verwendet wird, weil Mno.VAL eine Kompilierung ist Konstante. Daher ist es nicht erforderlich, die Mno-Klasse zu laden. Daher wird der statische Block von Mno nicht ausgeführt.

Sie können den statischen Block ausführen, indem manuell MnO Laden wie folgt:

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) Eigentlich haben Sie sich nicht, dass MnO Klasse so, wenn Kompilierung beginnen wird es konstant variabler VAL erzeugen und wenn die Ausführung beginnen, wenn Diese Variable wird benötigt, die von memory geladen wird. Daher ist die Klassenreferenz nicht erforderlich, damit static bock nicht ausgeführt wird.

2) Wenn eine Klasse diese Mno-Klasse zu diesem Zeitpunkt erweitert, wird der statische Block in die A-Klasse eingeschlossen, wenn Sie dies tun, dann wird dieser statische Block ausgeführt. zum Beispiel .. public class A erstreckt 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); 
    } 
}