问题描述
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内存中?
解决方法
根据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部分:
对作为常量变量(第4.12.4节)的字段的引用必须为 在编译时解析为常数表示的值V 变量的初始化程序。
如果此类字段是静态的,则不应对该字段进行任何引用 存在于代码中的二进制文件中,包括类或接口 声明了该字段。这样的字段必须始终看起来像是 已初始化(第12.4.2节);字段的默认初始值(如果 绝对不能观察到与V不同)。