为什么引用静态 final 字段不会触发类加载?

yel*_*owB 3 java compiler-construction jvm

我有一个这样的测试代码:

public class Constants {
public static String c1 = "C1";

static {
    System.out.println("Constants Class Loaded!");
}
}

public class Test {
    public static void main(String[] args) {
        String c1 = Constants.c1;
        System.out.println(c1);
    }
}
Run Code Online (Sandbox Code Playgroud)

它的输出是:

Constants Class Loaded!
C1
Run Code Online (Sandbox Code Playgroud)

因此,类 Constants 由 JVM 加载。但是如果我在类 Constants 的静态字段中添加一个 final 关键字:

public class Constants {
public static final String c1 = "C1";

static {
    System.out.println("Constants Class Loaded!");
}
}
Run Code Online (Sandbox Code Playgroud)

它的输出变为:

C1
Run Code Online (Sandbox Code Playgroud)

似乎没有加载类 Constants。

我的本地环境是:

OS: Win7 x64
JVM: JRockit (build R28.2.0-79-146777-1.6.0_29-20111005-1808-windows-ia32, compiled mode)
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是:

  • 为什么引用静态 final 字段不会触发类加载?JVM 遇到这个代码会做什么(字节码)?
  • 这种行为是否取决于特定的 JVM?或者这是Java语言规范中的规则?
  • 这有什么优点和缺点?

谢谢。

Sot*_*lis 6

为什么引用静态 final 字段不会触发类加载?JVM 遇到这个代码会做什么(字节码)?

JLS 说

类或接口类型 T 将在以下任何一项第一次出现之前立即初始化:

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

常量变量被定义为

常量变量是final原始类型或String使用常量表达式(第 15.28 节)初始化的类型的变量 。

所以你的字段是一个常量变量,访问它不会导致类型被初始化。

这种行为是否取决于特定的 JVM?或者这是Java语言规范中的规则?

Java 语言规范指定了这种行为。

这有什么优点和缺点?

缺点是它可能会引起混淆(如果您不了解 Java 语言规范的详细信息)。

优点是引用常量不会导致任何不必要的代码执行。