32

Who can explain what's going on?

public class MagicFinal {

    public static void main(String[] args) {
        System.out.println(A.s);
    }
}

class A {
    static {
        System.out.println("class has been loaded");
    }

    public static final String s = "final";

    public static final Integer i = 3;
    
        
}

Console :

final

What's it? I don't understand why the class has not been loaded, I know classes always load at the first call. Field s is in pool of string, I see that final modifier is magic.

If I delete final modifier (public static String s = "final" ) I will get

Console :

class has been loaded

final

Note: I have changed field i : public static final int i = 3; and show it in console. I got the same as in String situation. Why?

Community
  • 1
  • 1
idmitriev
  • 4,619
  • 4
  • 28
  • 44

2 Answers2

46

"final" is a string literal and as such is a compile-time constant expression. The value of a static final variable initialized with a compile-time constant expression is directly hardcoded into the class which references it, and no reference is made to the originating class. Therefore the initialization of the originating class does not occur.

As a side point, please note the distinction between class loading and class initialization: only the latter's occurrence is precisely specified by the JLS. Class loading can happen at any time.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • 1
    Ok , thank's a lot !! What about int ?? public static final int i = 3; // wont write class has been loaded public static final Integer i = 3; // write class has been loaded – idmitriev Sep 24 '13 at 10:48
  • 4
    Please read the definition of compile-time constant expression to which I have linked in my answer. `int` is a primitive value, `String` is the only special case of a reference-typed value which can be involved in a constant expression, and `Integer` is neither. – Marko Topolnik Sep 24 '13 at 10:52
  • @marko - Are you telling me that Class A is not getting loaded at all?? or is it a case of lazy initialization??? – TheLostMind Sep 24 '13 at 13:05
  • 2
    @X86 If `"class has been loaded"` doesn't print, then the class has not been initialized. Classes are always initialized lazily, as per the JLS. Class A may get *loaded* at any point or not at all, subject to the decision by the JVM runtime. Note that class loading is not supposed to cause any observable effects. – Marko Topolnik Sep 24 '13 at 13:10
  • I am sorry.. But I am still not quite getting it... A class may or may not be loaded... But once a class is loaded, it is initialized lazily.. is this correct??.. And in this case, String constants are substituted in the class, so, initialization of the class is not yet done.. only loading is done.. right? – TheLostMind Sep 24 '13 at 13:26
  • 1
    @x86 I don't follow you. Class A is not being initialized at all if the field in it is `static final`. It may or may not be loaded, but that has nothing to do with this story. It will most probably not be loaded, but there's nothing stopping the JVM from doing so. – Marko Topolnik Sep 24 '13 at 13:32
  • @MarkoTopolnik The last paragraph of your answer prompted [this question of mine](http://stackoverflow.com/q/19100002/1527084) – Geek Sep 30 '13 at 17:51
3

This is what is written in Java Language Specification {8.3.2.1 Initializers for Class Variables}. This must answer your question

One subtlety here is that, at run time, static variables that are final and that are initialized with compile-time constant values are initialized first. This also applies to such fields in interfaces (§9.3.1). These variables are “constants” that will never be observed to have their default initial values (§4.12.5), even by devious programs. See §12.4.2 and §13.4.9 for more discussion.

Michael Berry
  • 70,193
  • 21
  • 157
  • 216
Abhijith Nagarajan
  • 3,865
  • 18
  • 23
  • Seems like you're referring to *The Java Language Specification, Third Edition*. There are no such paragraph in *The Java® Language Specification Java SE 7 Edition*. – johnchen902 Sep 24 '13 at 11:08
  • Yes. That is right. I was looking into old edition but the statement holds good for JLS 7 as well. Below lines are from JLS7 At run-time, static fields that are final and that are initialized with constant expressions (§15.28) are initialized first (§12.4.2). This also applies to such fields in interfaces (§9.3.1). These fields are "constants" that will never be observed to have their default initial values (§4.12.5), even by devious programs (§13.4.9). – Abhijith Nagarajan Sep 24 '13 at 11:12