3

Example.java

public class Example {

    static final int i = 10;
    static int j = 20;
    static {
        System.out.println("Example class loaded and initialized");
    }
}

Use.java

import java.util.Scanner;
public class Use {
    public static void main(String args[]){
        Scanner sc = new Scanner(System.in);
        int ch = 1;
        while(ch != 0) {
            System.out.print("Enter choice: ");
            ch = sc.nextInt();

            if (ch == 1) {
                System.out.println("Example's i = " + Example.i);
            } else if(ch == 2){
                System.out.println("Example's j = " + Example.j);
            }
        }
    }
}

When I run with java -verbose:class Use, and give input as 1 then output is 10 i.e the constant i value. But Example class is not loaded yet. However, when I give input as 2, only then Example class is loaded into the JVM, as visible by the verbose output, and then static block inside Example is executed and also j's value initialized and then printed.

My Query is: If for the input 1 i.e when the static final (constant) value of a class Example is requested in another class Use, then from where is that constant value fetched if the class Example was never loaded into the JVM till then? When and how was the static final i intialized and store into the JVM memory?

  • 2
    Java may inline final static variables across classes at compilation(javac) time. This is to reduce the number of class loads. I could of sworn I saw a very similar question a few days ago. I'll see if I can find it. – PiRocks Aug 22 '20 at 08:25
  • 1
    Old question but has info about this:https://stackoverflow.com/questions/3524150/is-it-possible-to-disable-javacs-inlining-of-static-final-variables – PiRocks Aug 22 '20 at 08:29
  • @PiRocks that makes sense. Thanks for answering that and digging up the old question and providing a reference to that :) so, is my understanding correct: that in the compiled Use.class file 'System.out.println("Example's i = " + Example.i)' is actually 'System.out.println("Example's i = " + 10)' in bytecode form? – Harshit Rajput Aug 22 '20 at 09:22
  • 1
    Correct. You could check this for youself with `javap -v -p path/to/Use.class` – PiRocks Aug 22 '20 at 09:29
  • Awesome! I checked it now. It indeed is that. Thanks mate :) – Harshit Rajput Aug 22 '20 at 09:34
  • 1
    Related: [Java static final values replaced in code when compiling?](https://stackoverflow.com/questions/5173372/java-static-final-values-replaced-in-code-when-compiling) – Mark Rotteveel Aug 22 '20 at 18:27

1 Answers1

2

According to the Java language specification section 12.4.1 (emphasis added):

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

  • T is a class and an instance of T is created.

  • A static method declared by T is invoked.

  • A static field declared by T is assigned.

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

A constant variable is a final variable that is initialized with a constant expression. In your code, Example.i is a constant variable, and therefore does not cause the class to be loaded.

So if the class is not loaded, where does the value com from?

The language specification requires the compiler to inline its value. From section of binary compatibility 13.1:

  1. A reference to a field that is a constant variable (§4.12.4) must be resolved at compile time to the value V denoted by the constant variable's initializer.

    If such a field is static, then no reference to the field should be present in the code in a binary file, including the class or interface which declared the field. Such a field must always appear to have been initialized (§12.4.2); the default initial value for the field (if different than V) must never be observed.

Joni
  • 108,737
  • 14
  • 143
  • 193