Example.java
public class Example {
static final int i = 10;
static int j = 20;
static {
System.out.println("Example class loaded and initialized");
}
}
使用.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中,如详细输出所示,然后执行Example中的静态块,初始化并打印j
的值。
我的查询是:如果对于输入1
,即当在另一个类Use
中请求类Example
的静态最终(常量(值时,那么如果在此之前从未将类Example
加载到JVM中,则从哪里获取常量值?静态最终i
是何时以及如何初始化并存储到JVM内存中的?
根据Java语言规范第12.4.1节(增加强调(:
类或接口类型T将在首次出现以下任一情况:
T是一个类,并创建了T的实例。
调用由T声明的静态方法。
指定了一个由T声明的静态字段。
使用由T声明的静态字段,并且该字段不是常量变量(§4.12.4(
常量变量是用常量表达式初始化的最终变量。在您的代码中,Example.i
是一个常量变量,因此不会导致类被加载。
那么,如果没有加载类,那么com的值从哪里来?
语言规范要求编译器内联其值。来自二进制兼容性13.1部分:
对常量变量字段(§4.12.4(的引用必须是在编译时解析为由常数表示的值V变量的初始值设定项。
如果这样的字段是静态的,则不应引用该字段存在于二进制文件中的代码中,包括类或接口它声明了字段。这样一个领域似乎总是已初始化(§12.4.2(;字段的默认初始值(如果不同于V(。