92
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?

Neuron
  • 5,141
  • 5
  • 38
  • 59
Sthita
  • 1,750
  • 2
  • 19
  • 38

5 Answers5

139
  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;
  2. therefore your main class does not trigger the loading of the class containing the field;
  3. 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.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • 1
    But, then how does the value of the final variable in the class is evaluated without loading the class? – Sumit Desai May 31 '13 at 09:25
  • 18
    All evaluation happens at compile time and the end result is hardcoded into all places which reference the variable. – Marko Topolnik May 31 '13 at 09:26
  • 1
    So, if instead of a primitive variable, it is some Object, then such hardcoding will not be possible. Isn't it? So, in that case, will that class be loaded and static block will get executed? – Sumit Desai May 31 '13 at 09:28
  • 2
    Marko, Sumit's doubt is right also if instead of primitive, it is some Object, then such hardcoding will not be possible. Isn't it? So, in that case, will that class be loaded and static block will get executed? – Sthita May 31 '13 at 09:30
  • 8
    @SumitDesai Exactly, this works only for primitive values and string literals. For full detail read the [relevant chapter in the Java Language Specification](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.28) – Marko Topolnik May 31 '13 at 10:18
  • In case of static final String literal, it still is a compile time constant and will be hardcoded by the compiler. – Walter Laan May 31 '13 at 10:34
8

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; }
    
assylias
  • 321,522
  • 82
  • 660
  • 783
5

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);
    }
}
Xolve
  • 22,298
  • 21
  • 77
  • 125
1
  1. Actually you have not extends that Mno class so when compilation start it will generate constant of variable VAL and when execution start when that variable is needed its load thats from memory. So its not required that your class reference so that static bock is not executed.

  2. if class A extends class Mno, the static block is included in class A if you do this then that static block is executed. For example..

    public class A extends 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);
        }
    }
    
Neuron
  • 5,141
  • 5
  • 38
  • 59
0

As far as I know, it will be executed in order of appearance. For instance :

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

will print

  trace init1
  trace middle
  trace init2

I just tested it and the statics are initialized (=> print) when the class "Statique" is actually used and "executed" in another piece of code (my case I did "new Statique()".

Fabyen
  • 332
  • 3
  • 3
  • 2
    You're getting this output because you're loading the `Statique` class by doing `new Statique()`. While in the question asked, `Mno` class is not loaded at all. – RAS May 31 '13 at 09:31
  • @Fabyen , if i am creating object of Mno in test class like this : Mno anc=New Mno(); then its fine , but current scenario i am not doing that, my doubt is if i am removing final then the static block executes fine otherwise it doesn't execute, why so ?? – Sthita May 31 '13 at 09:35
  • 1
    Yep answer below is perfect. In the bytecode of Main.class (using Mno.VAL), 9090 is found hard coded. Remove final, compile, then use javap Main, you will see **getstatic #16; //Field Statique.VAL:I**. Put back final, compile, then use javap Main, you will see **sipush 9090**. – Fabyen May 31 '13 at 10:04
  • 1
    Because it's hardcoded in Main.class, there's no reason to load class MNO, hence there's no static initialization. – Fabyen May 31 '13 at 10:08
  • This answers the second question: "Which memory will be allocated first, the static final variable or the static block?" (lexical order) – Hauke Ingmar Schmidt Jun 04 '13 at 20:53