javajvm

Why reference to a static final field will not trigger class loading?


I have a testing code like this:

public class Constants {
public static String c1 = "C1";

static {
    System.out.println("Constants Class Loaded!");
}
}

public class Test {
    public static void main(String[] args) {
        String c1 = Constants.c1;
        System.out.println(c1);
    }
}

Its output is:

Constants Class Loaded!
C1

So, the class Constants is loaded by JVM. But if I add a final keyword to the static field in class Constants:

public class Constants {
public static final String c1 = "C1";

static {
    System.out.println("Constants Class Loaded!");
}
}

Its output changed to:

C1

It seems the class Constants is not loaded.

My local environment is:

OS: Win7 x64
JVM: JRockit (build R28.2.0-79-146777-1.6.0_29-20111005-1808-windows-ia32, compiled mode)

So, my questions are:

Thanks.


Solution

  • Why reference to a static final field will not trigger class loading? What will JVM do(bytecode) when it meets this code?

    The JLS says

    A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

    • [...]
    • A static field declared by T is used and the field is not a constant variable (§4.12.4).

    A constant variable is defined as

    A constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.28).

    So your field is such a constant variable and accessing it won't cause the type to be initialized.

    Is this behavior depending on specific JVM? Or this is a rule in Java language specification?

    The Java Language Specification specifies this behavior.

    What's the advantage & disadvantage of this?

    The disadvantage is the confusion it might cause (if you don't know the details of the Java Language specification).

    The advantage is that referring to constants doesn't cause any unnecessary execution of code.