编译时间常量

Compile Time Constant

我从 Compile-time constants and variables.

了解到什么是编译时间常量规则
  1. 宣布为最终
  2. 有原始类型或字符串类型
  3. 与声明同时初始化
  4. 用常量表达式初始化

final int x = 5;

但是我不明白为什么下面的代码没有:

final int x;
x = 5;

唯一不同的是上面第三点。 在不同行而不是同一行上进行初始化有何不同。

案例一final int x = 5;

public static void main(String[] args) {
    final int x = 5;
}

生成的字节码是:

  public static main([Ljava/lang/String;)V
   L0
    LINENUMBER 3 L0
    ICONST_5
    ISTORE 1
   L1
    LINENUMBER 4 L1
    RETURN
   L2
    LOCALVARIABLE args [Ljava/lang/String; L0 L2 0
    LOCALVARIABLE x I L1 L2 1
    MAXSTACK = 1
    MAXLOCALS = 2

案例二final int x; x = 5;

public static void main(String[] args) {
    final int x;
    x = 5;
}

生成的字节码是:

  public static main([Ljava/lang/String;)V
   L0
    LINENUMBER 4 L0
    ICONST_5
    ISTORE 1
   L1
    LINENUMBER 5 L1
    RETURN
   L2
    LOCALVARIABLE args [Ljava/lang/String; L0 L2 0
    LOCALVARIABLE x I L1 L2 1
    MAXSTACK = 1
    MAXLOCALS = 2

如您所见,除了行号之外,这两种情况没有区别。

事实上,在诸如 InteliJ 的 ide 中,您会看到提示(作为灯泡)将案例 2 的 2 行加入案例 1 中的 1 行。

如果您阅读 link 中的所有答案和评论,您将获得 ided,
对此你会更困惑而不是更明智。
这都是关于术语的,在这种情况下 未记录 术语。

这是 link:

中的一个答案的摘录

The JLS does not contain the phrase compile-time constant.
However, programmers often use the terms compile-time constant and constant interchangeably.

现在介绍编译器如何使用这两种情况。
如果您在两种方法的末尾添加此行:

System.out.println(x);


生成的字节码是:
案例 1

GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ICONST_5
INVOKEVIRTUAL java/io/PrintStream.println (I)V

以及 案例 2

GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ILOAD 1
INVOKEVIRTUAL java/io/PrintStream.println (I)V

第二种情况有所不同:ILOAD 1 而不是 ICONST_5
意思是在第一种情况下 x 被 5 替换,而在第二种情况下它不是,x 的值被调用(加载)以执行语句。

来自JLS Sec 4.12.4

constant variable is a final variable of primitive type or type String that is initialized with a constant expression (§15.28).

如果变量在未初始化的情况下声明,则根据定义它不是常量变量,即使您最终分配给它的值是常量表达式也是如此。