类加载与初始化:Java静态最终变量

时间:2020-08-22 08:22:05

标签: java memory jvm classloading in-class-initialization

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类尚未加载。 但是,当我以2的形式输入时,仅 Example 类被加载到JVM中,如详细输出所示,然后执行示例中的static块,还初始化j的值,然后打印。

我的查询是:如果对于输入1,即在另一个类Example中请求类Use的静态最终(常数)值时,那么如果之前从未将类Example从未加载到JVM中,则从哪里获取该常数值? 何时以及如何将静态最终i初始化并存储到JVM内存中?

1 个答案:

答案 0 :(得分:2)

根据Java language specification section 12.4.1(强调):

类或接口类型T将在即将被初始化之前 下列任何一项的首次出现:

  • T是一个类,并创建T的实例。

  • 调用由T声明的静态方法。

  • 分配了由T声明的静态字段。

  • 使用了T声明的静态字段,该字段不是常量变量(第4.12.4节)。

constant variable是用constant expression初始化的最终变量。在您的代码中,Example.i是一个常量变量,因此不会导致该类被加载。

因此,如果未加载该类,那么com的值从哪里来?

语言规范要求编译器内联其值。来自binary compatibility 13.1部分:

  1. 对作为常量变量(第4.12.4节)的字段的引用必须为 在编译时解析为常数表示的值V 变量的初始化程序。

    如果此类字段是静态的,则不应对该字段进行任何引用 存在于代码中的二进制文件中,包括类或接口 声明了该字段。这样的字段必须始终看起来像是 已初始化(第12.4.2节);字段的默认初始值(如果 绝对不能观察到与V不同)。