Class 加载与初始化:Java static final 变量

Class Loading vs Initialisation: Java static final variable

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

当我 运行 和 java -verbose:class Use 时,输入为 1 则输出为 10,即常量 i 值。但是 Example class 还没有加载。 但是,当我将输入作为 2 时, 只有 Example class 被加载到 JVM 中,如详细输出,然后执行 Example 中的静态块,并初始化并打印 j 的值。

我的查询是: 如果对于输入 1 即当 class Example 的静态最终(常量)值是在另一个 class Use 中请求,如果 class Example 直到那时才加载到 JVM 中,那么从哪里获取常量值? static final i 何时以及如何初始化并存储到 JVM 内存中?

根据Java language specification section 12.4.1(重点添加):

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).

一个constant variable is a final variable that is initialized with a constant expression。在您的代码中,Example.i 是一个常量变量,因此不会导致加载 class。

所以,如果 class 没有加载,值 com 从哪里来?

语言规范要求编译器内联它的值。来自 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.