Static block in Java not executed
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);
}
}
I know that a static
block executed when class loaded. But in this case the instance variable inside class Mno
is final
, because of that the static
block is not executing.
Why is that so? And if I would remove the final
, would it work fine?
Which memory will be allocated first, the static final
variable or the static
block?
If due to the final
access modifier the class does not get loaded, then how can the variable get memory?
Solution 1:
- A
static final int
field is a compile-time constant and its value is hardcoded into the destination class without a reference to its origin; - therefore your main class does not trigger the loading of the class containing the field;
- therefore the static initializer in that class is not executed.
In specific detail, the compiled bytecode corresponds to this:
public static void main(String arg[]){
System.out.println("**MAIN METHOD");
System.out.println(9090)
System.out.println(9190)
}
As soon as you remove final
, it is no longer a compile-time constant and the special behavior described above does not apply. The Mno
class is loaded as you expect and its static initializer executes.
Solution 2:
The reason why the class is not loaded is that VAL
is final
AND it is initialised with a constant expression (9090). If, and only if, those two conditions are met, the constant is evaluated at compile time and "hardcoded" where needed.
To prevent the expression from being evaluated at compile time (and to make the JVM load your class), you can either:
-
remove the final keyword:
static int VAL = 9090; //not a constant variable any more
-
or change the right hand side expression to something non constant (even if the variable is still final):
final static int VAL = getInt(); //not a constant expression any more static int getInt() { return 9090; }
Solution 3:
If you see generated bytecode using javap -v Test.class
, main() comes out like:
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
You can clearly see in "11: sipush 9090
" that static final value is directly used, because Mno.VAL is a compile time constant. Therefore it is not required to load Mno class. Hence static block of Mno is not executed.
You can execute the static block by manually loading Mno as below:
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);
}
}